Modified Quake to run as an Android application.

+ Add an Android Java application to interface with the Android Java runtime.
+ Add a downloader activity that enables the application to download the Quake data files from
  a web server.
+ Converted to C++. (Not nescessary, just convenient.)
+ Converted from OpenGL to OpenGL ES 1.0
+ Converted from an application to a shared library that's called from Java.
+ Support Android audio, events, and networking
+ Add minimal support for running with trackball, touch screen.
+ Remap key assignments for use with the T-mobile G1 keyboard.

Features

The UI is clunky, but servicable, at least on a T-mobile G1. You can play the
shareware levels, in both single-player and multi-player deathmatches over WiFi.

On keyboardless devices you can't do much, other than admire the attract mode and quit.

Quake actually contains two source trees: QuakeWorld and WinQuake. The difference is in
how the two games implement multiplayer. QuakeWorld is client/server, while WinQuake is
peer-to-peer. QuakeWorld has only been partially converted, and is not currently compiled
or run. We concentrated on WinQuake because it was able to reliably replay the timedemo demos.
We use timedemo in WinQuake to measure OpenGL performance.

Historical Note

This change is a roll-up of numerous changes that were made in the private Google Android
perforce9 tree during the development of Android. It doesn't seem worth trying to preserve
the individual commit history, so I'm checking all the changes in at one time. This code
snapshot was taken from the Cupcake branch.
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..f0760ab
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,128 @@
+# Quake game
+# This makefile builds both an activity and a shared library.
+
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build Quake activity
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Quake
+
+LOCAL_JNI_SHARED_LIBRARIES := libquake
+
+include $(BUILD_PACKAGE)
+
+# Build Quake Shared Library
+
+LOCAL_PATH:= $(LOCAL_PATH)/quake/src/WinQuake
+
+include $(CLEAR_VARS)
+
+# This isn't a test, but giving it a tests tag
+# means that this apk won't be installed by
+# default in any configuration.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Werror
+
+LOCAL_SRC_FILES:= \
+  cd_null.cpp \
+  cl_demo.cpp \
+  cl_input.cpp \
+  cl_main.cpp \
+  cl_parse.cpp \
+  cl_tent.cpp \
+  chase.cpp \
+  cmd.cpp \
+  common.cpp \
+  console.cpp \
+  crc.cpp \
+  cvar.cpp \
+  gl_draw.cpp \
+  gl_mesh.cpp \
+  gl_model.cpp \
+  gl_refrag.cpp \
+  gl_rlight.cpp \
+  gl_rmain.cpp \
+  gl_rmisc.cpp \
+  gl_rsurf.cpp \
+  gl_screen.cpp \
+  gl_vidandroid.cpp \
+  gl_warp.cpp \
+  host.cpp \
+  host_cmd.cpp \
+  keys.cpp \
+  main.cpp \
+  masterMain.cpp \
+  mathlib.cpp \
+  menu.cpp \
+  net_bsd.cpp \
+  net_dgrm.cpp \
+  net_loop.cpp \
+  net_main.cpp \
+  net_vcr.cpp \
+  net_udp.cpp \
+  nonintel.cpp \
+  pr_cmds.cpp \
+  pr_edict.cpp \
+  pr_exec.cpp \
+  r_part.cpp \
+  sbar.cpp \
+  snd_dma.cpp \
+  snd_mem.cpp \
+  snd_mix.cpp \
+  snd_android.cpp \
+  sv_main.cpp \
+  sv_phys.cpp \
+  sv_move.cpp \
+  sv_user.cpp \
+  sys_android.cpp \
+  view.cpp \
+  wad.cpp \
+  world.cpp \
+  zone.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libutils \
+	libmedia \
+	libEGL \
+	libGLESv1_CM
+
+LOCAL_MODULE := libquake
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Build stand-alone quake executable on device
+
+ifneq ($(BUILD_TINY_ANDROID),true)
+ifeq ($(TARGET_ARCH),arm)
+
+LOCAL_PATH:= $(TOP_LOCAL_PATH)/standalone
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= main.cpp
+
+LOCAL_SHARED_LIBRARIES := libc libm libui libquake libEGL libGLESv1_CM
+
+LOCAL_MODULE:= quake
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+endif
+endif
+
+endif # TARGET_SIMULATOR
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..045d44d
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/Quake/AndroidManifest.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.quake">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <application android:icon="@drawable/app_quake"
+            android:label="@string/quake_activity">
+        <activity android:name="QuakeActivity"
+                android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+            	android:launchMode="singleTask"
+            	android:screenOrientation="landscape"
+            	android:configChanges="orientation|keyboardHidden">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="DownloaderActivity"
+            android:label="@string/download_activity_title"
+            android:configChanges="orientation|keyboardHidden"
+            android:launchMode="singleTask" />
+    </application>
+</manifest>
diff --git a/README b/README
new file mode 100644
index 0000000..fc5761e
--- /dev/null
+++ b/README
@@ -0,0 +1,185 @@
+Quake
+
+In order to run Quake on the simulator and/or device, you must:
+
+	1) Build
+	2) Install
+	3) Run
+	4) Uninstalling Quake (this step is optional)
+
+Building Quake
+--------------
+
+Quake and libQuake are built by default, as part of the standard Android build.
+If for some reason you would like to build Quake manually, you can do so by
+using the mm command:
+
+$ cd $TOP/apps/Quake
+$ mm
+
+
+Installing Quake
+----------------
+
+Quake is not installed by default. To install Quake you need to copy the Quake executable
+files and data files to the device.
+
+Quake needs about 20 MB of space to store its data files. Quake files go on an external
+micro SD card (This is /sdcard/data/quake directory).
+
+Using the device with a microsd card:
+
+	Turn on phone, plug into your development PC/Mac using the supplied ADB cable.
+	cd $TOP/apps/Quake
+	adb remount
+	adb install $OUT/system/app/Quake.apk
+
+Make sure your device is not mounted as an USB Storage Device:
+    Press Home button on Phone
+    Press Menu
+    Select "SD card & phone storage
+    Make sure "Use for USB storage" is unchecked.
+
+Then install the Quake data files:
+
+	./setupdevicesdcard.sh
+	
+Using the emulator:
+
+	You can use Quake with the emulator, but you have to create and mount an sdcard image.
+	(Doing that is beyond the scope of this document.)
+	Once you've started the emulator with a sdcard image you can follow the directions for
+	a real device.
+
+
+Running Quake
+-------------
+
+Turn on the device
+
+Look for Quake in the Activities folder. Launch it as you would any other activity.
+It will take up to thirty seconds to start running.
+
+When Quake starts running it will display a console with some debug information, then
+go into an "attract mode" loop.
+
+Starting a game:
+
+Press space bar to bring up the main menu.
+The "Quake icon" should be next to the "Single Player" menu item. Press the
+"Enter" button twice to start the game.
+
+Controls:
+
+The Quake controls are customizable, depending upon the settings of config.cfg,
+but the defaults are:
+
+Android     PC Key    Command          Notes
+Keypad
+----------  --------- ---------------  ----------------------------------
+Alt Space   TAB       +showscores      Shows scores in multiplayer games
+DPad Enter  ENTER     +jump
+Menu        ESCAPE    togglemenu       Shows/hides menu
+space       SPACE     +jump
++           +         sizeup           Increases size of screen
+,           ,         +moveleft	       Strafe left
+-           -         sizedown
+.           .         +moveright       Strafe right
+/           /         impulse 10       Toggle weapons up
+0           0         impulse 0        
+1           1         impulse 1        Select weapon 1 (axe)
+2           2         impulse 2        Select weapon 2 (shotgun)
+3           3         impulse 3        Double-barrled shotgun
+4           4         impulse 4        Nailgun
+5           5         impulse 5        Super nailgun
+6           6         impulse 6        Grenade launcher
+7           7         impulse 7        Rocket Launcher
+8           8         impulse 8        Thunderbolt
+=           =         sizeup
+\           \         +mlook           Mouse look. (Not very useful, as there is no mouse.)
+Alt w       `         toggleconsole    Used to enter fancy commands.
+w           w         +forward
+s           s         +back
+a           a         +left
+d           d         +right
+q           q         +lookup
+z           z         +lookdown
+v           v         +movedown
+f           f         +moveup
+t           t         messagemode
+DPad Up     UPARROW   +forward
+DPad Down   DOWNARROW +back
+DPad Left   LEFTARROW +left
+DPad Right  RIGHTARROW+right
+Alt         ALT       +strafe
+@ or /      CTRL      +attack
+Cap         SHIFT     +speed
+Alt 1       F1        help              (This is just an advertisement in the shareware version.)
+Alt 2       F2        menu_save
+Alt 3       F3        menu_load
+Alt 4       F4        menu_options
+Alt 5       F5        menu_multiplayer
+Alt 6       F6        echo Quicksaving...; wait; save quick
+Alt 9       F9        echo Quickloading...; wait; load quick
+Alt 0       F10       quit
+Alt t       F11       zoom_in
+Alt y       F12       screenshot
+<none>      INS       +klook
+<none>      DEL       +lookdown
+<none>      PGDN      +lookup
+<none>      END       centerview
+<none>      MOUSE1    +attack
+<none>      MOUSE2    +forward
+<none>      MOUSE3    +mlook
+Alt z       PAUSE     pause
+Camera      HOME      ...not bound by default...
+-----
+
+Console Commands:
+
+timedemo demo#  run time demo # (1..3)
+god 	        turns on god mode
+fly 	        enables fly mode
+kill 	        commits suicide
+notarget 	enemies don't attack until provoked
+noclip 	    walk through walls
+give s # 	gives # (where # = a number) of shotgun shells
+give n # 	gives # of nails
+give r # 	gives # of rockets/grenades
+give c # 	gives # of cells
+give h # 	gives # of health
+give # 	    gives weapon #
+map e#m# 	warps to the episode and mission specified
+impulse -1 	quad cheat
+impulse 9 	all weapons and keys
+impulse 255 	quad cheat
+
+
+ 
+Uninstalling Quake
+------------------
+
+Quake has to be uninstalled in two parts:
+    a) the Quake.apk file
+    b) the data files on the sdcard
+
+Use the Phone UI to uninstall the Quake apk:
+
+    Press Home Key
+    Press Menu Key
+    Select Settings
+    Select Applications
+    Selct Manage Applications
+    Select Quake
+    Press "Uninstall"
+
+Make sure your device is not mounted as an USB Storage Device:
+    Press Home button on Phone
+    Press Menu
+    Select "SD card & phone storage
+    Make sure "Use for USB storage" is unchecked
+
+Then run this script to delete the Quake files on the sdcard:
+
+    cd $TOP/apps/Quake
+    ./cleanupdevicesdcard.sh
\ No newline at end of file
diff --git a/cleanupdevicesdcard.sh b/cleanupdevicesdcard.sh
new file mode 100755
index 0000000..3c5fbec
--- /dev/null
+++ b/cleanupdevicesdcard.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# Copy Quake's data files from perforce to the Android device's sd card.
+# Based on emulator.sh
+#
+
+# We need some internal functions defined in envsetup.sh, so start
+# by finding this file and sourcing it before anything else
+#
+function gettop
+{
+    TOPFILE=config/envsetup.make
+    if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
+        echo $TOP
+    else
+        if [ -f $TOPFILE ] ; then
+            echo $PWD
+        else
+            HERE=$PWD
+            T=
+            while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+                cd ..
+                T=$PWD
+            done
+            cd $HERE
+            if [ -f "$T/$TOPFILE" ]; then
+                echo $T
+            fi
+        fi
+    fi
+}
+
+T=$(gettop)
+if [ -z "$T" ] ; then
+    echo "please run your envsetup.sh script"
+    exit 1
+fi
+
+echo "top found at $T"
+
+echo "Removing Quake files and directories from the device's sdcard"
+
+adb shell rm /sdcard/data/quake/id1/glQuake/*
+adb shell rm /sdcard/data/quake/id1/glQuake/.DS_Store
+adb shell rmdir /sdcard/data/quake/glQuake
+adb shell rm /sdcard/data/quake/id1/*
+adb shell rm /sdcard/data/quake/id1/.DS_Store
+adb shell rmdir /sdcard/data/quake/id1
+adb shell rm /sdcard/data/quake/.DS_Store
+adb shell rmdir /sdcard/data/quake
+
+echo "Done."
\ No newline at end of file
diff --git a/quake/app/id1/config.cfg b/quake/app/id1/config.cfg
new file mode 100644
index 0000000..84f6a94
--- /dev/null
+++ b/quake/app/id1/config.cfg
Binary files differ
diff --git a/quake/src/QW/Makefile.Linux b/quake/src/QW/Makefile.Linux
old mode 100644
new mode 100755
diff --git a/quake/src/QW/Makefile.Solaris b/quake/src/QW/Makefile.Solaris
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/adivtab.h b/quake/src/QW/client/adivtab.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/anorm_dots.h b/quake/src/QW/client/anorm_dots.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/anorms.h b/quake/src/QW/client/anorms.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/asm_draw.h b/quake/src/QW/client/asm_draw.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/asm_i386.h b/quake/src/QW/client/asm_i386.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/block16.h b/quake/src/QW/client/block16.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/block8.h b/quake/src/QW/client/block8.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/bothdefs.h b/quake/src/QW/client/bothdefs.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/bspfile.h b/quake/src/QW/client/bspfile.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/buildnum.c b/quake/src/QW/client/buildnum.c
old mode 100644
new mode 100755
index dd20f13..dab42ae
--- a/quake/src/QW/client/buildnum.c
+++ b/quake/src/QW/client/buildnum.c
@@ -24,8 +24,8 @@
 

 // char *date = "Oct 24 1996";

 // char *time = "13:22:52";

-char *date = __DATE__ ;

-char *time = __TIME__ ;

+char *buildDate = __DATE__ ;

+char *buildTime = __TIME__ ;

 

 char *mon[12] = 

 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

@@ -46,14 +46,14 @@
 

 	for (m = 0; m < 11; m++)

 	{

-		if (_strnicmp( &date[0], mon[m], 3 ) == 0)

+		if (strncasecmp( &buildDate[0], mon[m], 3 ) == 0)

 			break;

 		d += mond[m];

 	}

 

-	d += atoi( &date[4] ) - 1;

+	d += atoi( &buildDate[4] ) - 1;

 

-	y = atoi( &date[7] ) - 1900;

+	y = atoi( &buildDate[7] ) - 1900;

 

 	b = d + (int)((y - 1) * 365.25);

 

@@ -64,9 +64,9 @@
 

 	b -= 34995; // Oct 24 1996

 

-	hr = (time[0] - '0') * 10 + (time[1] - '0');

-	min = (time[3] - '0') * 10 + (time[4] - '0');

-//	sec = (time[6] - '0') * 10 + (time[7] - '0');

+	hr = (buildTime[0] - '0') * 10 + (buildTime[1] - '0');

+	min = (buildTime[3] - '0') * 10 + (buildTime[4] - '0');

+//	sec = (buildTime[6] - '0') * 10 + (buildTime[7] - '0');

 

 	b *= 60*24;

 	b += hr * 60 + min;

diff --git a/quake/src/QW/client/cd_audio.c b/quake/src/QW/client/cd_audio.c
old mode 100644
new mode 100755
index 4e977b3..c5517d0
--- a/quake/src/QW/client/cd_audio.c
+++ b/quake/src/QW/client/cd_audio.c
@@ -1,6 +1,6 @@
-#include <dpmi.h>
+// #include <dpmi.h>
 #include "quakedef.h"
-#include "dosisms.h"
+// #include "dosisms.h"
 
 extern	cvar_t	bgmvolume;
 
@@ -235,6 +235,7 @@
 
 static void CDAudio_Reset(void)
 {
+#if 0
 	cdRequest->headerLength = 13;
 	cdRequest->unit = 0;
 	cdRequest->command = COMMAND_WRITE;
@@ -254,11 +255,14 @@
 	regs.x.es = cdRequestSegment;
 	regs.x.bx = cdRequestOffset;
 	dos_int86 (0x2f);
+	
+#endif
 }
 
 
 static void CDAudio_Eject(void)
 {
+#if 0
 	cdRequest->headerLength = 13;
 	cdRequest->unit = 0;
 	cdRequest->command = COMMAND_WRITE;
@@ -278,11 +282,15 @@
 	regs.x.es = cdRequestSegment;
 	regs.x.bx = cdRequestOffset;
 	dos_int86 (0x2f);
+
+#endif
+
 }
 
 
 static int CDAudio_GetAudioTrackInfo(byte track, int *start)
 {
+#if 0
 	byte	control;
 
 	cdRequest->headerLength = 13;
@@ -315,11 +323,17 @@
 	*start = readInfo->audioTrackInfo.start;
 	control = readInfo->audioTrackInfo.control & AUDIO_CONTROL_MASK;
 	return (control & AUDIO_CONTROL_DATA_TRACK);
+	
+#endif
+
+	return 0;
+
 }
 
 
 static int CDAudio_GetAudioDiskInfo(void)
 {
+#if 0
 	int n;
 
 	cdRequest->headerLength = 13;
@@ -364,12 +378,15 @@
 		}
 	}
 
+#endif
+
 	return 0;
 }
 
 
 static int CDAudio_GetAudioStatus(void)
 {
+#if 0
 	cdRequest->headerLength = 13;
 	cdRequest->unit = 0;
 	cdRequest->command = COMMAND_READ;
@@ -393,11 +410,14 @@
 	if (cdRequest->status & STATUS_ERROR_BIT)
 		return -1;
 	return 0;
+#endif
+	return 0;
 }
 
 
 static int CDAudio_MediaChange(void)
 {
+#if 0
 	cdRequest->headerLength = 13;
 	cdRequest->unit = 0;
 	cdRequest->command = COMMAND_READ;
@@ -419,6 +439,8 @@
 	dos_int86 (0x2f);
 
 	return readInfo->mediaChange.status;
+#endif
+	return 0;
 }
 
 
@@ -435,6 +457,8 @@
 	if (!initialized || !enabled)
 		return;
 
+#if 0
+
 	cdRequest->headerLength = 13;
 	cdRequest->unit = 0;
 	cdRequest->command = COMMAND_WRITE;
@@ -472,12 +496,16 @@
 	regs.x.bx = cdRequestOffset;
 	dos_int86 (0x2f);
 
+#endif
+
 	cdvolume = volume;
 }
 
 
 void CDAudio_Play(byte track, qboolean looping)
 {
+
+#if 0
 	if (!initialized || !enabled)
 		return;
 	
@@ -531,6 +559,8 @@
 		playing = false;
 		return;
 	}
+	
+#endif
 
 	playing = true;
 }
@@ -540,7 +570,8 @@
 {
 	if (!initialized || !enabled)
 		return;
-	
+
+#if 0
 	cdRequest->headerLength = 13;
 	cdRequest->unit = 0;
 	cdRequest->command = COMMAND_STOP_AUDIO;
@@ -551,6 +582,7 @@
 	regs.x.es = cdRequestSegment;
 	regs.x.bx = cdRequestOffset;
 	dos_int86 (0x2f);
+#endif
 
 	wasPlaying = playing;
 	playing = false;
@@ -568,6 +600,7 @@
 	if (!wasPlaying)
 		return;
 	
+#if 0
 	cdRequest->headerLength = 13;
 	cdRequest->unit = 0;
 	cdRequest->command = COMMAND_RESUME_AUDIO;
@@ -578,17 +611,18 @@
 	regs.x.es = cdRequestSegment;
 	regs.x.bx = cdRequestOffset;
 	dos_int86 (0x2f);
+#endif
 
 	playing = true;
 }
 
-
 static void CD_f (void)
 {
 	char	*command;
 	int		ret;
 	int		n;
 	int		startAddress;
+	startAddress = 0;
 
 	if (Cmd_Argc() < 2)
 		return;
@@ -692,7 +726,6 @@
 	}
 }
 
-
 void CDAudio_Update(void)
 {
 	int		ret;
@@ -764,6 +797,8 @@
 	char	*memory;
 	int		n;
 
+#if 0
+
 	if (cls.state == ca_dedicated)
 		return -1;
 
@@ -820,6 +855,8 @@
 	readInfoSegment = ptr2real(readInfo) >> 4;
 	readInfoOffset = ptr2real(readInfo) & 0xf;
 
+#endif
+
 	for (n = 0; n < 256; n++)
 		remap[n] = n;
 	initialized = true;
diff --git a/quake/src/QW/client/cd_linux.c b/quake/src/QW/client/cd_linux.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/cd_null.c b/quake/src/QW/client/cd_null.c
old mode 100644
new mode 100755
index ce8027f..389de61
--- a/quake/src/QW/client/cd_null.c
+++ b/quake/src/QW/client/cd_null.c
@@ -14,6 +14,10 @@
 {
 }
 
+void CDAudio_Pause(void)
+{
+}
+
 
 void CDAudio_Update(void)
 {
@@ -28,4 +32,4 @@
 
 void CDAudio_Shutdown(void)
 {
-}
\ No newline at end of file
+}
diff --git a/quake/src/QW/client/cd_win.c b/quake/src/QW/client/cd_win.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/cdaudio.h b/quake/src/QW/client/cdaudio.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/cl_cam.c b/quake/src/QW/client/cl_cam.c
old mode 100644
new mode 100755
index 4be041b..9ef8d4c
--- a/quake/src/QW/client/cl_cam.c
+++ b/quake/src/QW/client/cl_cam.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 included (GNU.txt) GNU General Public License for more details.

-

-You should have received a copy of the GNU General Public License

-along with this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 included (GNU.txt) GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 /* ZOID
  *
  * Player camera tracking in Spectator mode
@@ -40,9 +40,9 @@
 static int oldbuttons;
 
 // track high fragger
-cvar_t cl_hightrack = {"cl_hightrack", "0" };
+cvar_t cl_hightrack = CVAR2("cl_hightrack", "0" );
 
-cvar_t cl_chasecam = {"cl_chasecam", "0"};
+cvar_t cl_chasecam = CVAR2("cl_chasecam", "0");
 
 //cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" };
 //cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" };
diff --git a/quake/src/QW/client/cl_demo.c b/quake/src/QW/client/cl_demo.c
old mode 100644
new mode 100755
index 3f8d360..1c8959e
--- a/quake/src/QW/client/cl_demo.c
+++ b/quake/src/QW/client/cl_demo.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 included (GNU.txt) GNU General Public License for more details.

-

-You should have received a copy of the GNU General Public License

-along with this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 included (GNU.txt) GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 #include "quakedef.h"
 
@@ -424,7 +424,7 @@
 // serverdata
 	// send the info about the new client to all connected clients
 	memset(&buf, 0, sizeof(buf));
-	buf.data = buf_data;
+	buf.data = (byte*) buf_data;
 	buf.maxsize = sizeof(buf_data);
 
 // send the serverdata
diff --git a/quake/src/QW/client/cl_ents.c b/quake/src/QW/client/cl_ents.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/cl_input.c b/quake/src/QW/client/cl_input.c
old mode 100644
new mode 100755
index a92563f..b8f2047
--- a/quake/src/QW/client/cl_input.c
+++ b/quake/src/QW/client/cl_input.c
@@ -1,27 +1,27 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // cl.input.c  -- builds an intended movement command to send to the server
 
 #include "quakedef.h"
 
-cvar_t	cl_nodelta = {"cl_nodelta","0"};
+cvar_t	cl_nodelta = CVAR2("cl_nodelta","0");
 
 /*
 ===============================================================================
@@ -177,27 +177,31 @@
 	down = key->state & 1;
 	val = 0;
 	
-	if (impulsedown && !impulseup)
+	if (impulsedown && !impulseup) {
 		if (down)
 			val = 0.5;	// pressed and held this frame
 		else
 			val = 0;	//	I_Error ();
-	if (impulseup && !impulsedown)
+	}
+	if (impulseup && !impulsedown) {
 		if (down)
 			val = 0;	//	I_Error ();
 		else
 			val = 0;	// released this frame
-	if (!impulsedown && !impulseup)
+	}
+	if (!impulsedown && !impulseup) {
 		if (down)
 			val = 1.0;	// held the entire frame
 		else
 			val = 0;	// up the entire frame
-	if (impulsedown && impulseup)
+	}
+	if (impulsedown && impulseup) {
 		if (down)
 			val = 0.75;	// released and re-pressed this frame
 		else
 			val = 0.25;	// pressed and released this frame
-
+	}
+	
 	key->state &= 1;		// clear impulses
 	
 	return val;
@@ -208,17 +212,17 @@
 
 //==========================================================================
 
-cvar_t	cl_upspeed = {"cl_upspeed","200"};
-cvar_t	cl_forwardspeed = {"cl_forwardspeed","200", true};
-cvar_t	cl_backspeed = {"cl_backspeed","200", true};
-cvar_t	cl_sidespeed = {"cl_sidespeed","350"};
+cvar_t	cl_upspeed = CVAR2("cl_upspeed","200");
+cvar_t	cl_forwardspeed = CVAR3("cl_forwardspeed","200", true);
+cvar_t	cl_backspeed = CVAR3("cl_backspeed","200", true);
+cvar_t	cl_sidespeed = CVAR2("cl_sidespeed","350");
 
-cvar_t	cl_movespeedkey = {"cl_movespeedkey","2.0"};
+cvar_t	cl_movespeedkey = CVAR2("cl_movespeedkey","2.0");
 
-cvar_t	cl_yawspeed = {"cl_yawspeed","140"};
-cvar_t	cl_pitchspeed = {"cl_pitchspeed","150"};
+cvar_t	cl_yawspeed = CVAR2("cl_yawspeed","140");
+cvar_t	cl_pitchspeed = CVAR2("cl_pitchspeed","150");
 
-cvar_t	cl_anglespeedkey = {"cl_anglespeedkey","1.5"};
+cvar_t	cl_anglespeedkey = CVAR2("cl_anglespeedkey","1.5");
 
 
 /*
@@ -387,7 +391,7 @@
 	int			i;
 	usercmd_t	*cmd, *oldcmd;
 	int			checksumIndex;
-	int			lost;

+	int			lost;
 	int			seq_hash;
 
 	if (cls.demoplayback)
@@ -398,9 +402,9 @@
 	cmd = &cl.frames[i].cmd;
 	cl.frames[i].senttime = realtime;
 	cl.frames[i].receivedtime = -1;		// we haven't gotten a reply yet
-

-//	seq_hash = (cls.netchan.outgoing_sequence & 0xffff) ; // ^ QW_CHECK_HASH;

-	seq_hash = cls.netchan.outgoing_sequence;

+
+//	seq_hash = (cls.netchan.outgoing_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
+	seq_hash = cls.netchan.outgoing_sequence;
 
 	// get basic movement from keyboard
 	CL_BaseMove (cmd);
@@ -446,10 +450,10 @@
 	cmd = &cl.frames[i].cmd;
 	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
 
-	// calculate a checksum over the move commands

-	buf.data[checksumIndex] = COM_BlockSequenceCRCByte(

-		buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,

-		seq_hash);

+	// calculate a checksum over the move commands
+	buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
+		buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
+		seq_hash);
 
 	// request delta compression of entities
 	if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP-1)
diff --git a/quake/src/QW/client/cl_main.c b/quake/src/QW/client/cl_main.c
old mode 100644
new mode 100755
index 0e6e2a4..bd8097e
--- a/quake/src/QW/client/cl_main.c
+++ b/quake/src/QW/client/cl_main.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // cl_main.c  -- client main loop
 
 #include "quakedef.h"
@@ -34,49 +34,49 @@
 qboolean	noclip_anglehack;		// remnant from old quake
 
 
-cvar_t	rcon_password = {"rcon_password", "", false};
+cvar_t	rcon_password = CVAR3("rcon_password", "", false);
 
-cvar_t	rcon_address = {"rcon_address", ""};
+cvar_t	rcon_address = CVAR2("rcon_address", "");
 
-cvar_t	cl_timeout = {"cl_timeout", "60"};
+cvar_t	cl_timeout = CVAR2("cl_timeout", "60");
 
-cvar_t	cl_shownet = {"cl_shownet","0"};	// can be 0, 1, or 2
+cvar_t	cl_shownet = CVAR2("cl_shownet","0");	// can be 0, 1, or 2
 
-cvar_t	cl_sbar		= {"cl_sbar", "0", true};
-cvar_t	cl_hudswap	= {"cl_hudswap", "0", true};
-cvar_t	cl_maxfps	= {"cl_maxfps", "0", true};
+cvar_t	cl_sbar		= CVAR3("cl_sbar", "0", true);
+cvar_t	cl_hudswap	= CVAR3("cl_hudswap", "0", true);
+cvar_t	cl_maxfps	= CVAR3("cl_maxfps", "0", true);
 
-cvar_t	lookspring = {"lookspring","0", true};
-cvar_t	lookstrafe = {"lookstrafe","0", true};
-cvar_t	sensitivity = {"sensitivity","3", true};
+cvar_t	lookspring = CVAR3("lookspring","0", true);
+cvar_t	lookstrafe = CVAR3("lookstrafe","0", true);
+cvar_t	sensitivity = CVAR3("sensitivity","3", true);
 
-cvar_t	m_pitch = {"m_pitch","0.022", true};
-cvar_t	m_yaw = {"m_yaw","0.022"};
-cvar_t	m_forward = {"m_forward","1"};
-cvar_t	m_side = {"m_side","0.8"};
+cvar_t	m_pitch = CVAR3("m_pitch","0.022", true);
+cvar_t	m_yaw = CVAR2("m_yaw","0.022");
+cvar_t	m_forward = CVAR2("m_forward","1");
+cvar_t	m_side = CVAR2("m_side","0.8");
 
-cvar_t	entlatency = {"entlatency", "20"};
-cvar_t	cl_predict_players = {"cl_predict_players", "1"};
-cvar_t	cl_predict_players2 = {"cl_predict_players2", "1"};
-cvar_t	cl_solid_players = {"cl_solid_players", "1"};
+cvar_t	entlatency = CVAR2("entlatency", "20");
+cvar_t	cl_predict_players = CVAR2("cl_predict_players", "1");
+cvar_t	cl_predict_players2 = CVAR2("cl_predict_players2", "1");
+cvar_t	cl_solid_players = CVAR2("cl_solid_players", "1");
 
-cvar_t  localid = {"localid", ""};
+cvar_t  localid = CVAR2("localid", "");
 
 static qboolean allowremotecmd = true;
 
 //
 // info mirrors
 //
-cvar_t	password = {"password", "", false, true};
-cvar_t	spectator = {"spectator", "", false, true};
-cvar_t	name = {"name","unnamed", true, true};
-cvar_t	team = {"team","", true, true};
-cvar_t	skin = {"skin","", true, true};
-cvar_t	topcolor = {"topcolor","0", true, true};
-cvar_t	bottomcolor = {"bottomcolor","0", true, true};
-cvar_t	rate = {"rate","2500", true, true};
-cvar_t	noaim = {"noaim","0", true, true};
-cvar_t	msg = {"msg","1", true, true};
+cvar_t	password = CVAR4("password", "", false, true);
+cvar_t	spectator = CVAR4("spectator", "", false, true);
+cvar_t	name = CVAR4("name","unnamed", true, true);
+cvar_t	team = CVAR4("team","", true, true);
+cvar_t	skin = CVAR4("skin","", true, true);
+cvar_t	topcolor = CVAR4("topcolor","0", true, true);
+cvar_t	bottomcolor = CVAR4("bottomcolor","0", true, true);
+cvar_t	rate = CVAR4("rate","2500", true, true);
+cvar_t	noaim = CVAR4("noaim","0", true, true);
+cvar_t	msg = CVAR4("msg","1", true, true);
 
 extern cvar_t cl_hightrack;
 
@@ -116,9 +116,9 @@
 
 netadr_t	master_adr;				// address of the master server
 
-cvar_t	host_speeds = {"host_speeds","0"};			// set for running times
-cvar_t	show_fps = {"show_fps","0"};			// set for running times
-cvar_t	developer = {"developer","0"};
+cvar_t	host_speeds = CVAR2("host_speeds","0");			// set for running times
+cvar_t	show_fps = CVAR2("show_fps","0");			// set for running times
+cvar_t	developer = CVAR2("developer","0");
 
 int			fps_count;
 
@@ -212,8 +212,8 @@
 	connect_time = realtime+t2-t1;	// for retransmit requests
 
 	cls.qport = Cvar_VariableValue("qport");
-

-	Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING);

+
+	Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING);
 
 //	Con_Printf ("Connecting to %s...\n", cls.servername);
 	sprintf (data, "%c%c%c%cconnect %i %i %i \"%s\"\n",
@@ -405,7 +405,7 @@
 */
 void CL_Disconnect (void)
 {
-	byte	final[10];
+	char	final[10];
 
 	connect_time = -1;
 
@@ -426,9 +426,9 @@
 
 		final[0] = clc_stringcmd;
 		strcpy (final+1, "drop");
-		Netchan_Transmit (&cls.netchan, 6, final);
-		Netchan_Transmit (&cls.netchan, 6, final);
-		Netchan_Transmit (&cls.netchan, 6, final);
+		Netchan_Transmit (&cls.netchan, 6, (byte*) final);
+		Netchan_Transmit (&cls.netchan, 6, (byte*) final);
+		Netchan_Transmit (&cls.netchan, 6, (byte*) final);
 
 		cls.state = ca_disconnected;
 
@@ -625,7 +625,7 @@
 		if (*s)
 			s++;
 
-		if (!stricmp(key, pmodel_name) || !stricmp(key, emodel_name))
+		if (!strcasecmp(key, pmodel_name) || !strcasecmp(key, emodel_name))
 			continue;
 
 		Info_SetValueForKey (cls.userinfo, key, value, MAX_INFO_STRING);
@@ -1061,7 +1061,7 @@
 	Info_SetValueForKey (cls.userinfo, "rate", "2500", MAX_INFO_STRING);
 	Info_SetValueForKey (cls.userinfo, "msg", "1", MAX_INFO_STRING);
 	sprintf (st, "%4.2f-%04d", VERSION, build_number());
-	Info_SetValueForStarKey (cls.userinfo, "*ver", st, MAX_INFO_STRING);

+	Info_SetValueForStarKey (cls.userinfo, "*ver", st, MAX_INFO_STRING);
 
 	CL_InitInput ();
 	CL_InitTEnts ();
diff --git a/quake/src/QW/client/cl_parse.c b/quake/src/QW/client/cl_parse.c
old mode 100644
new mode 100755
index f6e28f5..a5c4371
--- a/quake/src/QW/client/cl_parse.c
+++ b/quake/src/QW/client/cl_parse.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // cl_parse.c  -- parse a message received from the server
 
 #include "quakedef.h"
@@ -334,7 +334,7 @@
 void CL_ParseDownload (void)
 {
 	int		size, percent;
-	byte	name[1024];
+	char	name[1024];
 	int		r;
 
 
@@ -549,7 +549,7 @@
 	// game directory
 	str = MSG_ReadString ();
 
-	if (stricmp(gamedirfile, str)) {
+	if (strcasecmp(gamedirfile, str)) {
 		// save current config
 		Host_WriteConfiguration (); 
 		cflag = true;
diff --git a/quake/src/QW/client/cl_pred.c b/quake/src/QW/client/cl_pred.c
old mode 100644
new mode 100755
index eff2871..dd21169
--- a/quake/src/QW/client/cl_pred.c
+++ b/quake/src/QW/client/cl_pred.c
@@ -1,27 +1,27 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 #include "quakedef.h"
 #include "winquake.h"
 
-cvar_t	cl_nopred = {"cl_nopred","0"};
-cvar_t	cl_pushlatency = {"pushlatency","-999"};
+cvar_t	cl_nopred = CVAR2("cl_nopred","0");
+cvar_t	cl_pushlatency = CVAR2("pushlatency","-999");
 
 extern	frame_t		*view_frame;
 
@@ -114,21 +114,21 @@
 	int			i;
 	float		f;
 	frame_t		*from, *to = NULL;
-	int			oldphysent;

-

+	int			oldphysent;
+
 	if (cl_pushlatency.value > 0)
 		Cvar_Set ("pushlatency", "0");
 
-	if (cl.paused)

-		return;

-

+	if (cl.paused)
+		return;
+
 	cl.time = realtime - cls.latency - cl_pushlatency.value*0.001;
 	if (cl.time > realtime)
 		cl.time = realtime;
 
 	if (cl.intermission)
-		return;

-

+		return;
+
 	if (!cl.validsequence)
 		return;
 
@@ -140,18 +140,18 @@
 	// this is the last frame received from the server
 	from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
 
-	// we can now render a frame

-	if (cls.state == ca_onserver)

-	{	// first update is the final signon stage

-		char		text[1024];

-

-		cls.state = ca_active;

-		sprintf (text, "QuakeWorld: %s", cls.servername);

-#ifdef _WIN32

-		SetWindowText (mainwindow, text);

-#endif

-	}

-

+	// we can now render a frame
+	if (cls.state == ca_onserver)
+	{	// first update is the final signon stage
+		char		text[1024];
+
+		cls.state = ca_active;
+		sprintf (text, "QuakeWorld: %s", cls.servername);
+#ifdef _WIN32
+		SetWindowText (mainwindow, text);
+#endif
+	}
+
 	if (cl_nopred.value)
 	{
 		VectorCopy (from->playerstate[cl.playernum].velocity, cl.simvel);
@@ -160,24 +160,24 @@
 	}
 
 	// predict forward until cl.time <= to->senttime
-	oldphysent = pmove.numphysent;

-	CL_SetSolidPlayers (cl.playernum);

-

-//	to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];

-

+	oldphysent = pmove.numphysent;
+	CL_SetSolidPlayers (cl.playernum);
+
+//	to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
+
 	for (i=1 ; i<UPDATE_BACKUP-1 && cls.netchan.incoming_sequence+i <
 			cls.netchan.outgoing_sequence; i++)
 	{
 		to = &cl.frames[(cls.netchan.incoming_sequence+i) & UPDATE_MASK];
 		CL_PredictUsercmd (&from->playerstate[cl.playernum]
-			, &to->playerstate[cl.playernum], &to->cmd, cl.spectator);

+			, &to->playerstate[cl.playernum], &to->cmd, cl.spectator);
 		if (to->senttime >= cl.time)
 			break;
 		from = to;
 	}
-

-	pmove.numphysent = oldphysent;

-

+
+	pmove.numphysent = oldphysent;
+
 	if (i == UPDATE_BACKUP-1 || !to)
 		return;		// net hasn't deliver packets in a long time...
 
diff --git a/quake/src/QW/client/cl_tent.c b/quake/src/QW/client/cl_tent.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/client.h b/quake/src/QW/client/client.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/cmd.c b/quake/src/QW/client/cmd.c
old mode 100644
new mode 100755
index b17520c..77e17c1
--- a/quake/src/QW/client/cmd.c
+++ b/quake/src/QW/client/cmd.c
@@ -1,748 +1,748 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// cmd.c -- Quake script command processing module

-

-#include "quakedef.h"

-

-void Cmd_ForwardToServer (void);

-

-#define	MAX_ALIAS_NAME	32

-

-typedef struct cmdalias_s

-{

-	struct cmdalias_s	*next;

-	char	name[MAX_ALIAS_NAME];

-	char	*value;

-} cmdalias_t;

-

-cmdalias_t	*cmd_alias;

-

-qboolean	cmd_wait;

-

-cvar_t cl_warncmd = {"cl_warncmd", "0"};

-

-//=============================================================================

-

-/*

-============

-Cmd_Wait_f

-

-Causes execution of the remainder of the command buffer to be delayed until

-next frame.  This allows commands like:

-bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"

-============

-*/

-void Cmd_Wait_f (void)

-{

-	cmd_wait = true;

-}

-

-/*

-=============================================================================

-

-						COMMAND BUFFER

-

-=============================================================================

-*/

-

-sizebuf_t	cmd_text;

-byte		cmd_text_buf[8192];

-

-/*

-============

-Cbuf_Init

-============

-*/

-void Cbuf_Init (void)

-{

-	cmd_text.data = cmd_text_buf;

-	cmd_text.maxsize = sizeof(cmd_text_buf);

-}

-

-/*

-============

-Cbuf_AddText

-

-Adds command text at the end of the buffer

-============

-*/

-void Cbuf_AddText (char *text)

-{

-	int		l;

-	

-	l = Q_strlen (text);

-

-	if (cmd_text.cursize + l >= cmd_text.maxsize)

-	{

-		Con_Printf ("Cbuf_AddText: overflow\n");

-		return;

-	}

-	SZ_Write (&cmd_text, text, Q_strlen (text));

-}

-

-

-/*

-============

-Cbuf_InsertText

-

-Adds command text immediately after the current command

-Adds a \n to the text

-FIXME: actually change the command buffer to do less copying

-============

-*/

-void Cbuf_InsertText (char *text)

-{

-	char	*temp;

-	int		templen;

-

-// copy off any commands still remaining in the exec buffer

-	templen = cmd_text.cursize;

-	if (templen)

-	{

-		temp = Z_Malloc (templen);

-		Q_memcpy (temp, cmd_text.data, templen);

-		SZ_Clear (&cmd_text);

-	}

-	else

-		temp = NULL;	// shut up compiler

-		

-// add the entire text of the file

-	Cbuf_AddText (text);

-	SZ_Write (&cmd_text, "\n", 1);

-// add the copied off data

-	if (templen)

-	{

-		SZ_Write (&cmd_text, temp, templen);

-		Z_Free (temp);

-	}

-}

-

-/*

-============

-Cbuf_Execute

-============

-*/

-void Cbuf_Execute (void)

-{

-	int		i;

-	char	*text;

-	char	line[1024];

-	int		quotes;

-	

-	while (cmd_text.cursize)

-	{

-// find a \n or ; line break

-		text = (char *)cmd_text.data;

-

-		quotes = 0;

-		for (i=0 ; i< cmd_text.cursize ; i++)

-		{

-			if (text[i] == '"')

-				quotes++;

-			if ( !(quotes&1) &&  text[i] == ';')

-				break;	// don't break if inside a quoted string

-			if (text[i] == '\n')

-				break;

-		}

-			

-				

-		memcpy (line, text, i);

-		line[i] = 0;

-		

-// delete the text from the command buffer and move remaining commands down

-// this is necessary because commands (exec, alias) can insert data at the

-// beginning of the text buffer

-

-		if (i == cmd_text.cursize)

-			cmd_text.cursize = 0;

-		else

-		{

-			i++;

-			cmd_text.cursize -= i;

-			Q_memcpy (text, text+i, cmd_text.cursize);

-		}

-

-// execute the command line

-		Cmd_ExecuteString (line);

-		

-		if (cmd_wait)

-		{	// skip out while text still remains in buffer, leaving it

-			// for next frame

-			cmd_wait = false;

-			break;

-		}

-	}

-}

-

-/*

-==============================================================================

-

-						SCRIPT COMMANDS

-

-==============================================================================

-*/

-

-/*

-===============

-Cmd_StuffCmds_f

-

-Adds command line parameters as script statements

-Commands lead with a +, and continue until a - or another +

-quake +prog jctest.qp +cmd amlev1

-quake -nosound +cmd amlev1

-===============

-*/

-void Cmd_StuffCmds_f (void)

-{

-	int		i, j;

-	int		s;

-	char	*text, *build, c;

-		

-// build the combined string to parse from

-	s = 0;

-	for (i=1 ; i<com_argc ; i++)

-	{

-		if (!com_argv[i])

-			continue;		// NEXTSTEP nulls out -NXHost

-		s += Q_strlen (com_argv[i]) + 1;

-	}

-	if (!s)

-		return;

-		

-	text = Z_Malloc (s+1);

-	text[0] = 0;

-	for (i=1 ; i<com_argc ; i++)

-	{

-		if (!com_argv[i])

-			continue;		// NEXTSTEP nulls out -NXHost

-		Q_strcat (text,com_argv[i]);

-		if (i != com_argc-1)

-			Q_strcat (text, " ");

-	}

-	

-// pull out the commands

-	build = Z_Malloc (s+1);

-	build[0] = 0;

-	

-	for (i=0 ; i<s-1 ; i++)

-	{

-		if (text[i] == '+')

-		{

-			i++;

-

-			for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)

-				;

-

-			c = text[j];

-			text[j] = 0;

-			

-			Q_strcat (build, text+i);

-			Q_strcat (build, "\n");

-			text[j] = c;

-			i = j-1;

-		}

-	}

-	

-	if (build[0])

-		Cbuf_InsertText (build);

-	

-	Z_Free (text);

-	Z_Free (build);

-}

-

-

-/*

-===============

-Cmd_Exec_f

-===============

-*/

-void Cmd_Exec_f (void)

-{

-	char	*f;

-	int		mark;

-

-	if (Cmd_Argc () != 2)

-	{

-		Con_Printf ("exec <filename> : execute a script file\n");

-		return;

-	}

-

-	// FIXME: is this safe freeing the hunk here???

-	mark = Hunk_LowMark ();

-	f = (char *)COM_LoadHunkFile (Cmd_Argv(1));

-	if (!f)

-	{

-		Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));

-		return;

-	}

-	if (!Cvar_Command () && (cl_warncmd.value || developer.value))

-		Con_Printf ("execing %s\n",Cmd_Argv(1));

-	

-	Cbuf_InsertText (f);

-	Hunk_FreeToLowMark (mark);

-}

-

-

-/*

-===============

-Cmd_Echo_f

-

-Just prints the rest of the line to the console

-===============

-*/

-void Cmd_Echo_f (void)

-{

-	int		i;

-	

-	for (i=1 ; i<Cmd_Argc() ; i++)

-		Con_Printf ("%s ",Cmd_Argv(i));

-	Con_Printf ("\n");

-}

-

-/*

-===============

-Cmd_Alias_f

-

-Creates a new command that executes a command string (possibly ; seperated)

-===============

-*/

-

-char *CopyString (char *in)

-{

-	char	*out;

-	

-	out = Z_Malloc (strlen(in)+1);

-	strcpy (out, in);

-	return out;

-}

-

-void Cmd_Alias_f (void)

-{

-	cmdalias_t	*a;

-	char		cmd[1024];

-	int			i, c;

-	char		*s;

-

-	if (Cmd_Argc() == 1)

-	{

-		Con_Printf ("Current alias commands:\n");

-		for (a = cmd_alias ; a ; a=a->next)

-			Con_Printf ("%s : %s\n", a->name, a->value);

-		return;

-	}

-

-	s = Cmd_Argv(1);

-	if (strlen(s) >= MAX_ALIAS_NAME)

-	{

-		Con_Printf ("Alias name is too long\n");

-		return;

-	}

-

-	// if the alias allready exists, reuse it

-	for (a = cmd_alias ; a ; a=a->next)

-	{

-		if (!strcmp(s, a->name))

-		{

-			Z_Free (a->value);

-			break;

-		}

-	}

-

-	if (!a)

-	{

-		a = Z_Malloc (sizeof(cmdalias_t));

-		a->next = cmd_alias;

-		cmd_alias = a;

-	}

-	strcpy (a->name, s);	

-

-// copy the rest of the command line

-	cmd[0] = 0;		// start out with a null string

-	c = Cmd_Argc();

-	for (i=2 ; i< c ; i++)

-	{

-		strcat (cmd, Cmd_Argv(i));

-		if (i != c)

-			strcat (cmd, " ");

-	}

-	strcat (cmd, "\n");

-	

-	a->value = CopyString (cmd);

-}

-

-/*

-=============================================================================

-

-					COMMAND EXECUTION

-

-=============================================================================

-*/

-

-typedef struct cmd_function_s

-{

-	struct cmd_function_s	*next;

-	char					*name;

-	xcommand_t				function;

-} cmd_function_t;

-

-

-#define	MAX_ARGS		80

-

-static	int			cmd_argc;

-static	char		*cmd_argv[MAX_ARGS];

-static	char		*cmd_null_string = "";

-static	char		*cmd_args = NULL;

-

-

-

-static	cmd_function_t	*cmd_functions;		// possible commands to execute

-

-/*

-============

-Cmd_Argc

-============

-*/

-int		Cmd_Argc (void)

-{

-	return cmd_argc;

-}

-

-/*

-============

-Cmd_Argv

-============

-*/

-char	*Cmd_Argv (int arg)

-{

-	if ( arg >= cmd_argc )

-		return cmd_null_string;

-	return cmd_argv[arg];	

-}

-

-/*

-============

-Cmd_Args

-

-Returns a single string containing argv(1) to argv(argc()-1)

-============

-*/

-char		*Cmd_Args (void)

-{

-	if (!cmd_args)

-		return "";

-	return cmd_args;

-}

-

-

-/*

-============

-Cmd_TokenizeString

-

-Parses the given string into command line tokens.

-============

-*/

-void Cmd_TokenizeString (char *text)

-{

-	int		i;

-	

-// clear the args from the last string

-	for (i=0 ; i<cmd_argc ; i++)

-		Z_Free (cmd_argv[i]);

-		

-	cmd_argc = 0;

-	cmd_args = NULL;

-	

-	while (1)

-	{

-// skip whitespace up to a /n

-		while (*text && *text <= ' ' && *text != '\n')

-		{

-			text++;

-		}

-		

-		if (*text == '\n')

-		{	// a newline seperates commands in the buffer

-			text++;

-			break;

-		}

-

-		if (!*text)

-			return;

-	

-		if (cmd_argc == 1)

-			 cmd_args = text;

-			

-		text = COM_Parse (text);

-		if (!text)

-			return;

-

-		if (cmd_argc < MAX_ARGS)

-		{

-			cmd_argv[cmd_argc] = Z_Malloc (Q_strlen(com_token)+1);

-			Q_strcpy (cmd_argv[cmd_argc], com_token);

-			cmd_argc++;

-		}

-	}

-	

-}

-

-

-/*

-============

-Cmd_AddCommand

-============

-*/

-void	Cmd_AddCommand (char *cmd_name, xcommand_t function)

-{

-	cmd_function_t	*cmd;

-	

-	if (host_initialized)	// because hunk allocation would get stomped

-		Sys_Error ("Cmd_AddCommand after host_initialized");

-		

-// fail if the command is a variable name

-	if (Cvar_VariableString(cmd_name)[0])

-	{

-		Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);

-		return;

-	}

-	

-// fail if the command already exists

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-	{

-		if (!Q_strcmp (cmd_name, cmd->name))

-		{

-			Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);

-			return;

-		}

-	}

-

-	cmd = Hunk_Alloc (sizeof(cmd_function_t));

-	cmd->name = cmd_name;

-	cmd->function = function;

-	cmd->next = cmd_functions;

-	cmd_functions = cmd;

-}

-

-/*

-============

-Cmd_Exists

-============

-*/

-qboolean	Cmd_Exists (char *cmd_name)

-{

-	cmd_function_t	*cmd;

-

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-	{

-		if (!Q_strcmp (cmd_name,cmd->name))

-			return true;

-	}

-

-	return false;

-}

-

-

-

-/*

-============

-Cmd_CompleteCommand

-============

-*/

-char *Cmd_CompleteCommand (char *partial)

-{

-	cmd_function_t	*cmd;

-	int				len;

-	cmdalias_t		*a;

-	

-	len = Q_strlen(partial);

-	

-	if (!len)

-		return NULL;

-		

-// check for exact match

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-		if (!strcmp (partial,cmd->name))

-			return cmd->name;

-	for (a=cmd_alias ; a ; a=a->next)

-		if (!strcmp (partial, a->name))

-			return a->name;

-

-// check for partial match

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-		if (!strncmp (partial,cmd->name, len))

-			return cmd->name;

-	for (a=cmd_alias ; a ; a=a->next)

-		if (!strncmp (partial, a->name, len))

-			return a->name;

-

-	return NULL;

-}

-

-#ifndef SERVERONLY		// FIXME

-/*

-===================

-Cmd_ForwardToServer

-

-adds the current command line as a clc_stringcmd to the client message.

-things like godmode, noclip, etc, are commands directed to the server,

-so when they are typed in at the console, they will need to be forwarded.

-===================

-*/

-void Cmd_ForwardToServer (void)

-{

-	if (cls.state == ca_disconnected)

-	{

-		Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));

-		return;

-	}

-	

-	if (cls.demoplayback)

-		return;		// not really connected

-

-	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);

-	SZ_Print (&cls.netchan.message, Cmd_Argv(0));

-	if (Cmd_Argc() > 1)

-	{

-		SZ_Print (&cls.netchan.message, " ");

-		SZ_Print (&cls.netchan.message, Cmd_Args());

-	}

-}

-

-// don't forward the first argument

-void Cmd_ForwardToServer_f (void)

-{

-	if (cls.state == ca_disconnected)

-	{

-		Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));

-		return;

-	}

-

-	if (Q_strcasecmp(Cmd_Argv(1), "snap") == 0) {

-		Cbuf_InsertText ("snap\n");

-		return;

-	}

-	

-	if (cls.demoplayback)

-		return;		// not really connected

-

-	if (Cmd_Argc() > 1)

-	{

-		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);

-		SZ_Print (&cls.netchan.message, Cmd_Args());

-	}

-}

-#else

-void Cmd_ForwardToServer (void)

-{

-}

-#endif

-

-/*

-============

-Cmd_ExecuteString

-

-A complete command line has been parsed, so try to execute it

-FIXME: lookupnoadd the token to speed search?

-============

-*/

-void	Cmd_ExecuteString (char *text)

-{	

-	cmd_function_t	*cmd;

-	cmdalias_t		*a;

-

-	Cmd_TokenizeString (text);

-			

-// execute the command line

-	if (!Cmd_Argc())

-		return;		// no tokens

-

-// check functions

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-	{

-		if (!Q_strcasecmp (cmd_argv[0],cmd->name))

-		{

-			if (!cmd->function)

-				Cmd_ForwardToServer ();

-			else

-				cmd->function ();

-			return;

-		}

-	}

-

-// check alias

-	for (a=cmd_alias ; a ; a=a->next)

-	{

-		if (!Q_strcasecmp (cmd_argv[0], a->name))

-		{

-			Cbuf_InsertText (a->value);

-			return;

-		}

-	}

-	

-// check cvars

-	if (!Cvar_Command () && (cl_warncmd.value || developer.value))

-		Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));

-	

-}

-

-

-

-/*

-================

-Cmd_CheckParm

-

-Returns the position (1 to argc-1) in the command's argument list

-where the given parameter apears, or 0 if not present

-================

-*/

-int Cmd_CheckParm (char *parm)

-{

-	int i;

-	

-	if (!parm)

-		Sys_Error ("Cmd_CheckParm: NULL");

-

-	for (i = 1; i < Cmd_Argc (); i++)

-		if (! Q_strcasecmp (parm, Cmd_Argv (i)))

-			return i;

-			

-	return 0;

-}

-

-/*

-============

-Cmd_Init

-============

-*/

-void Cmd_Init (void)

-{

-//

-// register our commands

-//

-	Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);

-	Cmd_AddCommand ("exec",Cmd_Exec_f);

-	Cmd_AddCommand ("echo",Cmd_Echo_f);

-	Cmd_AddCommand ("alias",Cmd_Alias_f);

-	Cmd_AddCommand ("wait", Cmd_Wait_f);

-#ifndef SERVERONLY

-	Cmd_AddCommand ("cmd", Cmd_ForwardToServer_f);

-#endif

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// cmd.c -- Quake script command processing module
+
+#include "quakedef.h"
+
+void Cmd_ForwardToServer (void);
+
+#define	MAX_ALIAS_NAME	32
+
+typedef struct cmdalias_s
+{
+	struct cmdalias_s	*next;
+	char	name[MAX_ALIAS_NAME];
+	char	*value;
+} cmdalias_t;
+
+cmdalias_t	*cmd_alias;
+
+qboolean	cmd_wait;
+
+cvar_t cl_warncmd = CVAR2("cl_warncmd", "0");
+
+//=============================================================================
+
+/*
+============
+Cmd_Wait_f
+
+Causes execution of the remainder of the command buffer to be delayed until
+next frame.  This allows commands like:
+bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
+============
+*/
+void Cmd_Wait_f (void)
+{
+	cmd_wait = true;
+}
+
+/*
+=============================================================================
+
+						COMMAND BUFFER
+
+=============================================================================
+*/
+
+sizebuf_t	cmd_text;
+byte		cmd_text_buf[8192];
+
+/*
+============
+Cbuf_Init
+============
+*/
+void Cbuf_Init (void)
+{
+	cmd_text.data = cmd_text_buf;
+	cmd_text.maxsize = sizeof(cmd_text_buf);
+}
+
+/*
+============
+Cbuf_AddText
+
+Adds command text at the end of the buffer
+============
+*/
+void Cbuf_AddText (char *text)
+{
+	int		l;
+	
+	l = Q_strlen (text);
+
+	if (cmd_text.cursize + l >= cmd_text.maxsize)
+	{
+		Con_Printf ("Cbuf_AddText: overflow\n");
+		return;
+	}
+	SZ_Write (&cmd_text, text, Q_strlen (text));
+}
+
+
+/*
+============
+Cbuf_InsertText
+
+Adds command text immediately after the current command
+Adds a \n to the text
+FIXME: actually change the command buffer to do less copying
+============
+*/
+void Cbuf_InsertText (char *text)
+{
+	char	*temp;
+	int		templen;
+
+// copy off any commands still remaining in the exec buffer
+	templen = cmd_text.cursize;
+	if (templen)
+	{
+		temp = Z_Malloc (templen);
+		Q_memcpy (temp, cmd_text.data, templen);
+		SZ_Clear (&cmd_text);
+	}
+	else
+		temp = NULL;	// shut up compiler
+		
+// add the entire text of the file
+	Cbuf_AddText (text);
+	SZ_Write (&cmd_text, "\n", 1);
+// add the copied off data
+	if (templen)
+	{
+		SZ_Write (&cmd_text, temp, templen);
+		Z_Free (temp);
+	}
+}
+
+/*
+============
+Cbuf_Execute
+============
+*/
+void Cbuf_Execute (void)
+{
+	int		i;
+	char	*text;
+	char	line[1024];
+	int		quotes;
+	
+	while (cmd_text.cursize)
+	{
+// find a \n or ; line break
+		text = (char *)cmd_text.data;
+
+		quotes = 0;
+		for (i=0 ; i< cmd_text.cursize ; i++)
+		{
+			if (text[i] == '"')
+				quotes++;
+			if ( !(quotes&1) &&  text[i] == ';')
+				break;	// don't break if inside a quoted string
+			if (text[i] == '\n' || text[i] == '\r')
+				break;
+		}
+			
+				
+		memcpy (line, text, i);
+		line[i] = 0;
+		
+// delete the text from the command buffer and move remaining commands down
+// this is necessary because commands (exec, alias) can insert data at the
+// beginning of the text buffer
+
+		if (i == cmd_text.cursize)
+			cmd_text.cursize = 0;
+		else
+		{
+			i++;
+			cmd_text.cursize -= i;
+			Q_memcpy (text, text+i, cmd_text.cursize);
+		}
+
+// execute the command line
+		Cmd_ExecuteString (line);
+		
+		if (cmd_wait)
+		{	// skip out while text still remains in buffer, leaving it
+			// for next frame
+			cmd_wait = false;
+			break;
+		}
+	}
+}
+
+/*
+==============================================================================
+
+						SCRIPT COMMANDS
+
+==============================================================================
+*/
+
+/*
+===============
+Cmd_StuffCmds_f
+
+Adds command line parameters as script statements
+Commands lead with a +, and continue until a - or another +
+quake +prog jctest.qp +cmd amlev1
+quake -nosound +cmd amlev1
+===============
+*/
+void Cmd_StuffCmds_f (void)
+{
+	int		i, j;
+	int		s;
+	char	*text, *build, c;
+		
+// build the combined string to parse from
+	s = 0;
+	for (i=1 ; i<com_argc ; i++)
+	{
+		if (!com_argv[i])
+			continue;		// NEXTSTEP nulls out -NXHost
+		s += Q_strlen (com_argv[i]) + 1;
+	}
+	if (!s)
+		return;
+		
+	text = Z_Malloc (s+1);
+	text[0] = 0;
+	for (i=1 ; i<com_argc ; i++)
+	{
+		if (!com_argv[i])
+			continue;		// NEXTSTEP nulls out -NXHost
+		Q_strcat (text,com_argv[i]);
+		if (i != com_argc-1)
+			Q_strcat (text, " ");
+	}
+	
+// pull out the commands
+	build = Z_Malloc (s+1);
+	build[0] = 0;
+	
+	for (i=0 ; i<s-1 ; i++)
+	{
+		if (text[i] == '+')
+		{
+			i++;
+
+			for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
+				;
+
+			c = text[j];
+			text[j] = 0;
+			
+			Q_strcat (build, text+i);
+			Q_strcat (build, "\n");
+			text[j] = c;
+			i = j-1;
+		}
+	}
+	
+	if (build[0])
+		Cbuf_InsertText (build);
+	
+	Z_Free (text);
+	Z_Free (build);
+}
+
+
+/*
+===============
+Cmd_Exec_f
+===============
+*/
+void Cmd_Exec_f (void)
+{
+	char	*f;
+	int		mark;
+
+	if (Cmd_Argc () != 2)
+	{
+		Con_Printf ("exec <filename> : execute a script file\n");
+		return;
+	}
+
+	// FIXME: is this safe freeing the hunk here???
+	mark = Hunk_LowMark ();
+	f = (char *)COM_LoadHunkFile (Cmd_Argv(1));
+	if (!f)
+	{
+		Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
+		return;
+	}
+	if (!Cvar_Command () && (cl_warncmd.value || developer.value))
+		Con_Printf ("execing %s\n",Cmd_Argv(1));
+	
+	Cbuf_InsertText (f);
+	Hunk_FreeToLowMark (mark);
+}
+
+
+/*
+===============
+Cmd_Echo_f
+
+Just prints the rest of the line to the console
+===============
+*/
+void Cmd_Echo_f (void)
+{
+	int		i;
+	
+	for (i=1 ; i<Cmd_Argc() ; i++)
+		Con_Printf ("%s ",Cmd_Argv(i));
+	Con_Printf ("\n");
+}
+
+/*
+===============
+Cmd_Alias_f
+
+Creates a new command that executes a command string (possibly ; seperated)
+===============
+*/
+
+char *CopyString (char *in)
+{
+	char	*out;
+	
+	out = Z_Malloc (strlen(in)+1);
+	strcpy (out, in);
+	return out;
+}
+
+void Cmd_Alias_f (void)
+{
+	cmdalias_t	*a;
+	char		cmd[1024];
+	int			i, c;
+	char		*s;
+
+	if (Cmd_Argc() == 1)
+	{
+		Con_Printf ("Current alias commands:\n");
+		for (a = cmd_alias ; a ; a=a->next)
+			Con_Printf ("%s : %s\n", a->name, a->value);
+		return;
+	}
+
+	s = Cmd_Argv(1);
+	if (strlen(s) >= MAX_ALIAS_NAME)
+	{
+		Con_Printf ("Alias name is too long\n");
+		return;
+	}
+
+	// if the alias allready exists, reuse it
+	for (a = cmd_alias ; a ; a=a->next)
+	{
+		if (!strcmp(s, a->name))
+		{
+			Z_Free (a->value);
+			break;
+		}
+	}
+
+	if (!a)
+	{
+		a = Z_Malloc (sizeof(cmdalias_t));
+		a->next = cmd_alias;
+		cmd_alias = a;
+	}
+	strcpy (a->name, s);	
+
+// copy the rest of the command line
+	cmd[0] = 0;		// start out with a null string
+	c = Cmd_Argc();
+	for (i=2 ; i< c ; i++)
+	{
+		strcat (cmd, Cmd_Argv(i));
+		if (i != c)
+			strcat (cmd, " ");
+	}
+	strcat (cmd, "\n");
+	
+	a->value = CopyString (cmd);
+}
+
+/*
+=============================================================================
+
+					COMMAND EXECUTION
+
+=============================================================================
+*/
+
+typedef struct cmd_function_s
+{
+	struct cmd_function_s	*next;
+	char					*name;
+	xcommand_t				function;
+} cmd_function_t;
+
+
+#define	MAX_ARGS		80
+
+static	int			cmd_argc;
+static	char		*cmd_argv[MAX_ARGS];
+static	char		*cmd_null_string = "";
+static	char		*cmd_args = NULL;
+
+
+
+static	cmd_function_t	*cmd_functions;		// possible commands to execute
+
+/*
+============
+Cmd_Argc
+============
+*/
+int		Cmd_Argc (void)
+{
+	return cmd_argc;
+}
+
+/*
+============
+Cmd_Argv
+============
+*/
+char	*Cmd_Argv (int arg)
+{
+	if ( arg >= cmd_argc )
+		return cmd_null_string;
+	return cmd_argv[arg];	
+}
+
+/*
+============
+Cmd_Args
+
+Returns a single string containing argv(1) to argv(argc()-1)
+============
+*/
+char		*Cmd_Args (void)
+{
+	if (!cmd_args)
+		return "";
+	return cmd_args;
+}
+
+
+/*
+============
+Cmd_TokenizeString
+
+Parses the given string into command line tokens.
+============
+*/
+void Cmd_TokenizeString (char *text)
+{
+	int		i;
+	
+// clear the args from the last string
+	for (i=0 ; i<cmd_argc ; i++)
+		Z_Free (cmd_argv[i]);
+		
+	cmd_argc = 0;
+	cmd_args = NULL;
+	
+	while (1)
+	{
+// skip whitespace up to a /n
+		while (*text && *text <= ' ' && *text != '\n')
+		{
+			text++;
+		}
+		
+		if (*text == '\n')
+		{	// a newline seperates commands in the buffer
+			text++;
+			break;
+		}
+
+		if (!*text)
+			return;
+	
+		if (cmd_argc == 1)
+			 cmd_args = text;
+			
+		text = COM_Parse (text);
+		if (!text)
+			return;
+
+		if (cmd_argc < MAX_ARGS)
+		{
+			cmd_argv[cmd_argc] = Z_Malloc (Q_strlen(com_token)+1);
+			Q_strcpy (cmd_argv[cmd_argc], com_token);
+			cmd_argc++;
+		}
+	}
+	
+}
+
+
+/*
+============
+Cmd_AddCommand
+============
+*/
+void	Cmd_AddCommand (char *cmd_name, xcommand_t function)
+{
+	cmd_function_t	*cmd;
+	
+	if (host_initialized)	// because hunk allocation would get stomped
+		Sys_Error ("Cmd_AddCommand after host_initialized");
+		
+// fail if the command is a variable name
+	if (Cvar_VariableString(cmd_name)[0])
+	{
+		Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
+		return;
+	}
+	
+// fail if the command already exists
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+	{
+		if (!Q_strcmp (cmd_name, cmd->name))
+		{
+			Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
+			return;
+		}
+	}
+
+	cmd = Hunk_Alloc (sizeof(cmd_function_t));
+	cmd->name = cmd_name;
+	cmd->function = function;
+	cmd->next = cmd_functions;
+	cmd_functions = cmd;
+}
+
+/*
+============
+Cmd_Exists
+============
+*/
+qboolean	Cmd_Exists (char *cmd_name)
+{
+	cmd_function_t	*cmd;
+
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+	{
+		if (!Q_strcmp (cmd_name,cmd->name))
+			return true;
+	}
+
+	return false;
+}
+
+
+
+/*
+============
+Cmd_CompleteCommand
+============
+*/
+char *Cmd_CompleteCommand (char *partial)
+{
+	cmd_function_t	*cmd;
+	int				len;
+	cmdalias_t		*a;
+	
+	len = Q_strlen(partial);
+	
+	if (!len)
+		return NULL;
+		
+// check for exact match
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+		if (!strcmp (partial,cmd->name))
+			return cmd->name;
+	for (a=cmd_alias ; a ; a=a->next)
+		if (!strcmp (partial, a->name))
+			return a->name;
+
+// check for partial match
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+		if (!strncmp (partial,cmd->name, len))
+			return cmd->name;
+	for (a=cmd_alias ; a ; a=a->next)
+		if (!strncmp (partial, a->name, len))
+			return a->name;
+
+	return NULL;
+}
+
+#ifndef SERVERONLY		// FIXME
+/*
+===================
+Cmd_ForwardToServer
+
+adds the current command line as a clc_stringcmd to the client message.
+things like godmode, noclip, etc, are commands directed to the server,
+so when they are typed in at the console, they will need to be forwarded.
+===================
+*/
+void Cmd_ForwardToServer (void)
+{
+	if (cls.state == ca_disconnected)
+	{
+		Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
+		return;
+	}
+	
+	if (cls.demoplayback)
+		return;		// not really connected
+
+	MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+	SZ_Print (&cls.netchan.message, Cmd_Argv(0));
+	if (Cmd_Argc() > 1)
+	{
+		SZ_Print (&cls.netchan.message, " ");
+		SZ_Print (&cls.netchan.message, Cmd_Args());
+	}
+}
+
+// don't forward the first argument
+void Cmd_ForwardToServer_f (void)
+{
+	if (cls.state == ca_disconnected)
+	{
+		Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
+		return;
+	}
+
+	if (Q_strcasecmp(Cmd_Argv(1), "snap") == 0) {
+		Cbuf_InsertText ("snap\n");
+		return;
+	}
+	
+	if (cls.demoplayback)
+		return;		// not really connected
+
+	if (Cmd_Argc() > 1)
+	{
+		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+		SZ_Print (&cls.netchan.message, Cmd_Args());
+	}
+}
+#else
+void Cmd_ForwardToServer (void)
+{
+}
+#endif
+
+/*
+============
+Cmd_ExecuteString
+
+A complete command line has been parsed, so try to execute it
+FIXME: lookupnoadd the token to speed search?
+============
+*/
+void	Cmd_ExecuteString (char *text)
+{	
+	cmd_function_t	*cmd;
+	cmdalias_t		*a;
+
+	Cmd_TokenizeString (text);
+			
+// execute the command line
+	if (!Cmd_Argc())
+		return;		// no tokens
+
+// check functions
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+	{
+		if (!Q_strcasecmp (cmd_argv[0],cmd->name))
+		{
+			if (!cmd->function)
+				Cmd_ForwardToServer ();
+			else
+				cmd->function ();
+			return;
+		}
+	}
+
+// check alias
+	for (a=cmd_alias ; a ; a=a->next)
+	{
+		if (!Q_strcasecmp (cmd_argv[0], a->name))
+		{
+			Cbuf_InsertText (a->value);
+			return;
+		}
+	}
+	
+// check cvars
+	if (!Cvar_Command () && (cl_warncmd.value || developer.value))
+		Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
+	
+}
+
+
+
+/*
+================
+Cmd_CheckParm
+
+Returns the position (1 to argc-1) in the command's argument list
+where the given parameter apears, or 0 if not present
+================
+*/
+int Cmd_CheckParm (char *parm)
+{
+	int i;
+	
+	if (!parm)
+		Sys_Error ("Cmd_CheckParm: NULL");
+
+	for (i = 1; i < Cmd_Argc (); i++)
+		if (! Q_strcasecmp (parm, Cmd_Argv (i)))
+			return i;
+			
+	return 0;
+}
+
+/*
+============
+Cmd_Init
+============
+*/
+void Cmd_Init (void)
+{
+//
+// register our commands
+//
+	Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
+	Cmd_AddCommand ("exec",Cmd_Exec_f);
+	Cmd_AddCommand ("echo",Cmd_Echo_f);
+	Cmd_AddCommand ("alias",Cmd_Alias_f);
+	Cmd_AddCommand ("wait", Cmd_Wait_f);
+#ifndef SERVERONLY
+	Cmd_AddCommand ("cmd", Cmd_ForwardToServer_f);
+#endif
+}
+
diff --git a/quake/src/QW/client/cmd.h b/quake/src/QW/client/cmd.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/common.c b/quake/src/QW/client/common.c
old mode 100644
new mode 100755
index 8fcf5d4..f0592dc
--- a/quake/src/QW/client/common.c
+++ b/quake/src/QW/client/common.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // common.c -- misc functions used in client and server
 
 #include <ctype.h>
@@ -38,7 +38,7 @@
 static char	*safeargvs[NUM_SAFE_ARGVS] =
 	{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse"};
 
-cvar_t	registered = {"registered","0"};
+cvar_t	registered = CVAR2("registered","0");
 
 qboolean	com_modified;	// set true if using non-id files
 
@@ -767,7 +767,7 @@
 			break;
 		string[l] = c;
 		l++;
-	} while (l < sizeof(string)-1);
+	} while (l < (int) sizeof(string)-1);
 	
 	string[l] = 0;
 	
@@ -787,7 +787,7 @@
 			break;
 		string[l] = c;
 		l++;
-	} while (l < sizeof(string)-1);
+	} while (l < (int) sizeof(string)-1);
 	
 	string[l] = 0;
 	
@@ -1120,11 +1120,13 @@
 	if (!h)
 	{
 		Con_Printf ("Playing shareware version.\n");
+#if 0
 #ifndef SERVERONLY
 // FIXME DEBUG -- only temporary
 		if (com_modified)
 			Sys_Error ("You must have the registered version to play QuakeWorld");
 #endif
+#endif
 		return;
 	}
 
@@ -1450,7 +1452,7 @@
 	
 	while (remaining)
 	{
-		if (remaining < sizeof(buf))
+		if (remaining < (int) sizeof(buf))
 			count = remaining;
 		else
 			count = sizeof(buf);
@@ -2034,7 +2036,7 @@
 	if (*(v = Info_ValueForKey(s, key))) {
 		// key exists, make sure we have enough room for new value, if we don't,
 		// don't change it!
-		if (strlen(value) - strlen(v) + strlen(s) > maxsize) {
+		if ((int) (strlen(value) - strlen(v) + strlen(s)) > maxsize) {
 			Con_Printf ("Info string length exceeded\n");
 			return;
 		}
diff --git a/quake/src/QW/client/common.h b/quake/src/QW/client/common.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/console.c b/quake/src/QW/client/console.c
old mode 100644
new mode 100755
index ab4c402..bcd596a
--- a/quake/src/QW/client/console.c
+++ b/quake/src/QW/client/console.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // console.c
 
 #include "quakedef.h"
@@ -32,7 +32,7 @@
 float		con_cursorspeed = 4;
 
 
-cvar_t		con_notifytime = {"con_notifytime","3"};		//seconds
+cvar_t		con_notifytime = CVAR2("con_notifytime","3");		//seconds
 
 #define	NUM_CON_TIMES 4
 float		con_times[NUM_CON_TIMES];	// realtime time the line was generated
@@ -514,7 +514,7 @@
 		}
 
 		s = chat_buffer;
-		if (chat_bufferlen > (vid.width>>3)-(skip+1))
+		if (chat_bufferlen > (int) ((vid.width>>3)-(skip+1)))
 			s += chat_bufferlen - ((vid.width>>3)-(skip+1));
 		x = 0;
 		while(s[x])
@@ -595,7 +595,7 @@
 		x = con_linewidth - ((con_linewidth * 7) / 40);
 		y = x - strlen(text) - 8;
 		i = con_linewidth/3;
-		if (strlen(text) > i) {
+		if ((int) strlen(text) > i) {
 			y = x - i - 11;
 			strncpy(dlbar, text, i);
 			dlbar[i] = 0;
@@ -623,7 +623,7 @@
 
 		// draw it
 		y = con_vislines-22 + 8;
-		for (i = 0; i < strlen(dlbar); i++)
+		for (i = 0; i < (int) strlen(dlbar); i++)
 			Draw_Character ( (i+1)<<3, y, dlbar[i]);
 	}
 
diff --git a/quake/src/QW/client/console.h b/quake/src/QW/client/console.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/crc.c b/quake/src/QW/client/crc.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/crc.h b/quake/src/QW/client/crc.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/cvar.c b/quake/src/QW/client/cvar.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/cvar.h b/quake/src/QW/client/cvar.h
old mode 100644
new mode 100755
index a102136..9754636
--- a/quake/src/QW/client/cvar.h
+++ b/quake/src/QW/client/cvar.h
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // cvar.h
 
 /*
@@ -63,6 +63,11 @@
 	struct cvar_s *next;
 } cvar_t;
 
+// Helper macro to avoid missing initializer warnings 
+#define CVAR2(NAME, STRING) {(NAME),(STRING), 0, 0, 0.0f, (struct cvar_s*) 0}
+#define CVAR3(NAME, STRING, ARCHIVE) {(NAME), (STRING), (ARCHIVE), 0, 0.0f, (struct cvar_s*) 0}
+#define CVAR4(NAME, STRING, ARCHIVE, INFO) {(NAME), (STRING), (ARCHIVE), (INFO), 0.0f, (struct cvar_s*) 0}
+
 void 	Cvar_RegisterVariable (cvar_t *variable);
 // registers a cvar that allready has the name, string, and optionally the
 // archive elements set.
diff --git a/quake/src/QW/client/d_copy.s b/quake/src/QW/client/d_copy.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_draw.asm b/quake/src/QW/client/d_draw.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_draw.s b/quake/src/QW/client/d_draw.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_draw16.asm b/quake/src/QW/client/d_draw16.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_draw16.s b/quake/src/QW/client/d_draw16.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_edge.c b/quake/src/QW/client/d_edge.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_fill.c b/quake/src/QW/client/d_fill.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_iface.h b/quake/src/QW/client/d_iface.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_ifacea.h b/quake/src/QW/client/d_ifacea.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_init.c b/quake/src/QW/client/d_init.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_local.h b/quake/src/QW/client/d_local.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_modech.c b/quake/src/QW/client/d_modech.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_part.c b/quake/src/QW/client/d_part.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_parta.asm b/quake/src/QW/client/d_parta.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_parta.s b/quake/src/QW/client/d_parta.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_polysa.asm b/quake/src/QW/client/d_polysa.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_polysa.s b/quake/src/QW/client/d_polysa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_polyse.c b/quake/src/QW/client/d_polyse.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_scan.c b/quake/src/QW/client/d_scan.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_scana.asm b/quake/src/QW/client/d_scana.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_scana.s b/quake/src/QW/client/d_scana.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_sky.c b/quake/src/QW/client/d_sky.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_spr8.asm b/quake/src/QW/client/d_spr8.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_spr8.s b/quake/src/QW/client/d_spr8.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_sprite.c b/quake/src/QW/client/d_sprite.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_surf.c b/quake/src/QW/client/d_surf.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_vars.c b/quake/src/QW/client/d_vars.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_varsa.asm b/quake/src/QW/client/d_varsa.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_varsa.s b/quake/src/QW/client/d_varsa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/d_zpoint.c b/quake/src/QW/client/d_zpoint.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/docs.txt b/quake/src/QW/client/docs.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/draw.c b/quake/src/QW/client/draw.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/draw.h b/quake/src/QW/client/draw.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/exitscrn.txt b/quake/src/QW/client/exitscrn.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_draw.c b/quake/src/QW/client/gl_draw.c
old mode 100644
new mode 100755
index ec435ae..f79564c
--- a/quake/src/QW/client/gl_draw.c
+++ b/quake/src/QW/client/gl_draw.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 // draw.c -- this is the only file outside the refresh that touches the
 // vid buffer
@@ -26,9 +26,9 @@
 extern unsigned char d_15to8table[65536];
 extern cvar_t crosshair, cl_crossx, cl_crossy, crosshaircolor;
 
-cvar_t		gl_nobind = {"gl_nobind", "0"};
-cvar_t		gl_max_size = {"gl_max_size", "1024"};
-cvar_t		gl_picmip = {"gl_picmip", "0"};
+cvar_t		gl_nobind = CVAR2("gl_nobind", "0");
+cvar_t		gl_max_size = CVAR2("gl_max_size", "1024");
+cvar_t		gl_picmip = CVAR2("gl_picmip", "0");
 
 byte		*draw_chars;				// 8*8 graphic characters
 qpic_t		*draw_disc;
@@ -416,7 +416,7 @@
 
 	sprintf (ver, "%4.2f", VERSION);
 	dest = cb->data + 320 + 320*186 - 11 - 8*strlen(ver);
-	for (x=0 ; x<strlen(ver) ; x++)
+	for (x=0 ; x< (int) strlen(ver) ; x++)
 		Draw_CharToConback (ver[x], dest+(x<<3));
 
 #if 0
@@ -516,6 +516,9 @@
 
 	GL_Bind (char_texture);
 
+#ifdef USE_OPENGLES
+	DrawQuad(x, y, 8, 8, fcol, frow, size, size);
+#else
 	glBegin (GL_QUADS);
 	glTexCoord2f (fcol, frow);
 	glVertex2f (x, y);
@@ -526,6 +529,7 @@
 	glTexCoord2f (fcol, frow + size);
 	glVertex2f (x, y+8);
 	glEnd ();
+#endif
 }
 
 /*
@@ -573,6 +577,9 @@
 		glColor4ubv ( pColor );
 		GL_Bind (cs_texture);
 
+#ifdef USE_OPENGLES
+        DrawQuad(x - 4, y - 4, 16, 16, 0, 0, 1, 1);
+#else
 		glBegin (GL_QUADS);
 		glTexCoord2f (0, 0);
 		glVertex2f (x - 4, y - 4);
@@ -583,6 +590,7 @@
 		glTexCoord2f (0, 1);
 		glVertex2f (x - 4, y+12);
 		glEnd ();
+#endif
 		
 		glTexEnvf ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
 	} else if (crosshair.value)
@@ -619,6 +627,9 @@
 	gl = (glpic_t *)pic->data;
 	glColor4f (1,1,1,1);
 	GL_Bind (gl->texnum);
+#ifdef USE_OPENGLES
+    DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
+#else
 	glBegin (GL_QUADS);
 	glTexCoord2f (gl->sl, gl->tl);
 	glVertex2f (x, y);
@@ -629,6 +640,7 @@
 	glTexCoord2f (gl->sl, gl->th);
 	glVertex2f (x, y+pic->height);
 	glEnd ();
+#endif
 }
 
 /*
@@ -649,6 +661,9 @@
 	glCullFace(GL_FRONT);
 	glColor4f (1,1,1,alpha);
 	GL_Bind (gl->texnum);
+#ifdef USE_OPENGLES
+    DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
+#else
 	glBegin (GL_QUADS);
 	glTexCoord2f (gl->sl, gl->tl);
 	glVertex2f (x, y);
@@ -659,6 +674,7 @@
 	glTexCoord2f (gl->sl, gl->th);
 	glVertex2f (x, y+pic->height);
 	glEnd ();
+#endif
 	glColor4f (1,1,1,1);
 	glEnable(GL_ALPHA_TEST);
 	glDisable (GL_BLEND);
@@ -685,6 +701,9 @@
 	
 	glColor4f (1,1,1,1);
 	GL_Bind (gl->texnum);
+#ifdef USE_OPENGLES
+    DrawQuad(x, y, width, height, newsl, newtl, newsh - newsl, newth - newtl);
+#else
 	glBegin (GL_QUADS);
 	glTexCoord2f (newsl, newtl);
 	glVertex2f (x, y);
@@ -695,6 +714,7 @@
 	glTexCoord2f (newsl, newth);
 	glVertex2f (x, y+height);
 	glEnd ();
+#endif
 }
 
 /*
@@ -747,12 +767,15 @@
 		}
 	}
 
-	glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+	glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
 
 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
 	glColor3f (1,1,1);
+#ifdef USE_OPENGLES
+	DrawQuad(x, y, pic->width, pic->height, 0, 0, 1, 1);
+#else
 	glBegin (GL_QUADS);
 	glTexCoord2f (0, 0);
 	glVertex2f (x, y);
@@ -763,6 +786,7 @@
 	glTexCoord2f (0, 1);
 	glVertex2f (x, y+pic->height);
 	glEnd ();
+#endif
 }
 
 
@@ -794,7 +818,7 @@
 		sprintf (ver, "GL (%4.2f) QuakeWorld", GLQUAKE_VERSION);
 #endif
 		x = vid.conwidth - (strlen(ver)*8 + 11) - (vid.conwidth*8/320)*7;
-		for (i=0 ; i<strlen(ver) ; i++)
+		for (i=0 ; i< (int) strlen(ver) ; i++)
 			Draw_Character (x + i * 8, y, ver[i] | 0x80);
 	}
 }
@@ -812,6 +836,9 @@
 {
 	glColor3f (1,1,1);
 	GL_Bind (*(int *)draw_backtile->data);
+#ifdef USE_OPENGLES
+	DrawQuad(x, y, w, h, x/64.0, y/64.0, w/64.0, h/64.0);
+#else
 	glBegin (GL_QUADS);
 	glTexCoord2f (x/64.0, y/64.0);
 	glVertex2f (x, y);
@@ -822,6 +849,7 @@
 	glTexCoord2f ( x/64.0, (y+h)/64.0 );
 	glVertex2f (x, y+h);
 	glEnd ();
+#endif
 }
 
 
@@ -839,6 +867,9 @@
 		host_basepal[c*3+1]/255.0,
 		host_basepal[c*3+2]/255.0);
 
+#ifdef USE_OPENGLES
+	DrawQuad_NoTex(x, y, w, h);
+#else
 	glBegin (GL_QUADS);
 
 	glVertex2f (x,y);
@@ -847,6 +878,7 @@
 	glVertex2f (x, y+h);
 
 	glEnd ();
+#endif
 	glColor3f (1,1,1);
 	glEnable (GL_TEXTURE_2D);
 }
@@ -863,6 +895,10 @@
 	glEnable (GL_BLEND);
 	glDisable (GL_TEXTURE_2D);
 	glColor4f (0, 0, 0, 0.8);
+
+#ifdef USE_OPENGLES
+	DrawQuad_NoTex(0, 0, vid.width, vid.height);
+#else
 	glBegin (GL_QUADS);
 
 	glVertex2f (0,0);
@@ -871,6 +907,7 @@
 	glVertex2f (0, vid.height);
 
 	glEnd ();
+#endif
 	glColor4f (1,1,1,1);
 	glEnable (GL_TEXTURE_2D);
 	glDisable (GL_BLEND);
@@ -892,9 +929,13 @@
 {
 	if (!draw_disc)
 		return;
+#ifdef USE_OPENGLES
+	// !!! Implement this
+#else
 	glDrawBuffer  (GL_FRONT);
 	Draw_Pic (vid.width - 24, 0, draw_disc);
 	glDrawBuffer  (GL_BACK);
+#endif
 }
 
 
@@ -923,7 +964,11 @@
 
 	glMatrixMode(GL_PROJECTION);
     glLoadIdentity ();
+#ifdef USE_OPENGLES
+	glOrthof (0, vid.width, vid.height, 0, -99999, 99999);
+#else
 	glOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
+#endif
 
 	glMatrixMode(GL_MODELVIEW);
     glLoadIdentity ();
@@ -1077,6 +1122,22 @@
 		}
 }
 
+void glTexImage2DHelper( GLenum target,
+	 GLint level,
+	 GLint internalformat,
+	 GLsizei width,
+	 GLsizei height,
+	 GLint border,
+	 GLenum format,
+	 GLenum type,
+	 const GLvoid *pixels )
+{
+	// In full OpenGL The internalformat can be 1..4, to indicate how many components of the data are valid.
+	// OpenGL ES requires the internalformat argument match the format for glTexImage2D.
+	
+	glTexImage2D(target, level, format, width, height, border, format, type, pixels);
+}
+
 /*
 ===============
 GL_Upload32
@@ -1096,12 +1157,12 @@
 	scaled_width >>= (int)gl_picmip.value;
 	scaled_height >>= (int)gl_picmip.value;
 
-	if (scaled_width > gl_max_size.value)
+	if (scaled_width > (int) gl_max_size.value)
 		scaled_width = gl_max_size.value;
-	if (scaled_height > gl_max_size.value)
+	if (scaled_height > (int) gl_max_size.value)
 		scaled_height = gl_max_size.value;
 
-	if (scaled_width * scaled_height > sizeof(scaled)/4)
+	if (scaled_width * scaled_height > (int) sizeof(scaled)/4)
 		Sys_Error ("GL_LoadTexture: too big");
 
 	samples = alpha ? gl_alpha_format : gl_solid_format;
@@ -1124,7 +1185,7 @@
 	{
 		if (!mipmap)
 		{
-			glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+			glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 			goto done;
 		}
 		memcpy (scaled, data, width*height*4);
@@ -1132,7 +1193,7 @@
 	else
 		GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
 
-	glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+	glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
 	if (mipmap)
 	{
 		int		miplevel;
@@ -1148,7 +1209,7 @@
 			if (scaled_height < 1)
 				scaled_height = 1;
 			miplevel++;
-			glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+			glTexImage2DHelper (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
 		}
 	}
 done: ;
@@ -1203,7 +1264,7 @@
 	if (scaled_height > gl_max_size.value)
 		scaled_height = gl_max_size.value;
 
-	if (scaled_width * scaled_height > sizeof(scaled))
+	if (scaled_width * scaled_height > (int) sizeof(scaled))
 		Sys_Error ("GL_LoadTexture: too big");
 
 	samples = 1; // alpha ? gl_alpha_format : gl_solid_format;
@@ -1214,7 +1275,11 @@
 	{
 		if (!mipmap)
 		{
+#ifdef USE_OPENGLES
+			glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, data);
+#else
 			glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
+#endif
 			goto done;
 		}
 		memcpy (scaled, data, width*height);
@@ -1222,7 +1287,12 @@
 	else
 		GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
 
+#ifdef USE_OPENGLES
+	glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled);
+#else
 	glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
+#endif
+
 	if (mipmap)
 	{
 		int		miplevel;
@@ -1238,7 +1308,11 @@
 			if (scaled_height < 1)
 				scaled_height = 1;
 			miplevel++;
+#ifdef USE_OPENGLES
+			glCompressedTexImage2D (GL_TEXTURE_2D, miplevel, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled);
+#else
 			glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
+#endif
 		}
 	}
 done: ;
@@ -1367,12 +1441,62 @@
 {
 	if (!gl_mtexable)
 		return;
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
 #ifndef __linux__ // no multitexture under Linux yet
 	qglSelectTextureSGIS(target);
 #endif
+#endif
 	if (target == oldtarget) 
 		return;
 	cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture;
 	currenttexture = cnttextures[target-TEXTURE0_SGIS];
 	oldtarget = target;
 }
+
+
+// OpenGL ES compatible DrawQuad utility
+
+void DrawQuad_NoTex(float x, float y, float w, float h)
+{
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
+	short index[4] = {0, 1, 2, 3};
+	glVertexPointer( 2, GL_FLOAT, 0, vertex);
+	glDrawElements(GL_TRIANGLE_FAN, 4, GL_SHORT, index);
+}
+
+void DrawQuad(float x, float y, float w, float h, float u, float v, float uw, float vh)
+{
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+    float texcoord[2*4] = {u, v, u + uw, v, u + uw, v + vh, u, v + vh};
+	float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
+	unsigned short index[4] = {0, 1, 2, 3};
+	glTexCoordPointer( 2, GL_FLOAT, 0, texcoord);
+	glVertexPointer( 2, GL_FLOAT, 0, vertex);
+	glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index);
+}
+
+#ifdef USE_OPENGLES
+
+// Reimplementation of OpenGL functions that are missing in OpenGL ES
+
+void glColor3f(GLfloat r, GLfloat g, GLfloat b)
+{
+	glColor4f(r, g, b, 1.0f);
+}
+
+void glColor4fv(GLfloat* pColor)
+{
+	glColor4f(pColor[0], pColor[1], pColor[2], pColor[3]);
+}
+
+void glColor4ubv(unsigned char* pColor)
+{
+	glColor4f(pColor[0] / 255.0f, pColor[1] / 255.0f, pColor[2] / 255.0f, pColor[3] / 255.0f);
+}
+
+#endif
diff --git a/quake/src/QW/client/gl_mesh.c b/quake/src/QW/client/gl_mesh.c
old mode 100644
new mode 100755
index 6622057..d0f0c0e
--- a/quake/src/QW/client/gl_mesh.c
+++ b/quake/src/QW/client/gl_mesh.c
@@ -210,6 +210,7 @@
 	//

 	numorder = 0;

 	numcommands = 0;

+	besttype = 0;

 	memset (used, 0, sizeof(used));

 	for (i=0 ; i<pheader->numtris ; i++)

 	{

diff --git a/quake/src/QW/client/gl_model.c b/quake/src/QW/client/gl_model.c
old mode 100644
new mode 100755
index 14aa019..edf3887
--- a/quake/src/QW/client/gl_model.c
+++ b/quake/src/QW/client/gl_model.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // models.c -- model loading and caching
 
 // models are the only shared resource between a client and server running
@@ -38,7 +38,7 @@
 model_t	mod_known[MAX_MOD_KNOWN];
 int		mod_numknown;
 
-cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", true};
+cvar_t gl_subdivide_size = CVAR3("gl_subdivide_size", "128", true);
 
 /*
 ===============
@@ -1170,11 +1170,11 @@
 // swap all the lumps
 	mod_base = (byte *)header;
 
-	for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
+	for (i=0 ; i< (int) sizeof(dheader_t)/4 ; i++)
 		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
 
 // checksum all of the map, except for entities
-	mod->checksum = 0;

+	mod->checksum = 0;
 	mod->checksum2 = 0;
 
 	for (i = 0; i < HEADER_LUMPS; i++) {
@@ -1182,11 +1182,11 @@
 			continue;
 		mod->checksum ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, 
 			header->lumps[i].filelen);
-

-		if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)

-			continue;

-		mod->checksum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, 

-			header->lumps[i].filelen);

+
+		if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)
+			continue;
+		mod->checksum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, 
+			header->lumps[i].filelen);
 	}
 	
 
@@ -1459,7 +1459,7 @@
 			// save 8 bit texels for the player model to remap
 			if (!strcmp(loadmodel->name,"progs/player.mdl"))
 			{
-				if (s > sizeof(player_8bit_texels))
+				if (s > (int) sizeof(player_8bit_texels))
 					Sys_Error ("Player skin too large");
 				memcpy (player_8bit_texels, (byte *)(pskintype + 1), s);
 			}
diff --git a/quake/src/QW/client/gl_model.h b/quake/src/QW/client/gl_model.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_ngraph.c b/quake/src/QW/client/gl_ngraph.c
old mode 100644
new mode 100755
index 21e541e..255a10e
--- a/quake/src/QW/client/gl_ngraph.c
+++ b/quake/src/QW/client/gl_ngraph.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // gl_ngraph.c
 
 #include "quakedef.h"
@@ -117,7 +117,7 @@
 	
     GL_Bind(netgraphtexture);
 
-	glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 
+	glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 
 		NET_TIMINGS, NET_GRAPHHEIGHT, 0, GL_RGBA, 
 		GL_UNSIGNED_BYTE, ngraph_pixels);
 
@@ -126,6 +126,11 @@
 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
 	x = 8;
+	
+#ifdef USE_OPENGLES
+	glColor4f (1,1,1,1);
+	DrawQuad(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1);
+#else
 	glColor3f (1,1,1);
 	glBegin (GL_QUADS);
 	glTexCoord2f (0, 0);
@@ -137,5 +142,6 @@
 	glTexCoord2f (0, 1);
 	glVertex2f (x, y+NET_GRAPHHEIGHT);
 	glEnd ();
+#endif
 }
 
diff --git a/quake/src/QW/client/gl_refrag.c b/quake/src/QW/client/gl_refrag.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_rlight.c b/quake/src/QW/client/gl_rlight.c
old mode 100644
new mode 100755
index f74a345..8f89684
--- a/quake/src/QW/client/gl_rlight.c
+++ b/quake/src/QW/client/gl_rlight.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // r_light.c
 
 #include "quakedef.h"
@@ -110,6 +110,9 @@
 		return;
 	}
 
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
 	glBegin (GL_TRIANGLE_FAN);
 //	glColor3f (0.2,0.1,0.0);
 //	glColor3f (0.2,0.1,0.05); // changed dimlight effect
@@ -130,6 +133,7 @@
 		glVertex3fv (v);
 	}
 	glEnd ();
+#endif
 }
 
 /*
diff --git a/quake/src/QW/client/gl_rmain.c b/quake/src/QW/client/gl_rmain.c
old mode 100644
new mode 100755
index 3294abe..d85cee0
--- a/quake/src/QW/client/gl_rmain.c
+++ b/quake/src/QW/client/gl_rmain.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // r_main.c
 
 #include "quakedef.h"
@@ -73,31 +73,31 @@
 
 void R_MarkLeaves (void);
 
-cvar_t	r_norefresh = {"r_norefresh","0"};
-cvar_t	r_drawentities = {"r_drawentities","1"};
-cvar_t	r_drawviewmodel = {"r_drawviewmodel","1"};
-cvar_t	r_speeds = {"r_speeds","0"};
-cvar_t	r_fullbright = {"r_fullbright","0"};
-cvar_t	r_lightmap = {"r_lightmap","0"};
-cvar_t	r_shadows = {"r_shadows","0"};
-cvar_t	r_mirroralpha = {"r_mirroralpha","1"};
-cvar_t	r_wateralpha = {"r_wateralpha","1"};
-cvar_t	r_dynamic = {"r_dynamic","1"};
-cvar_t	r_novis = {"r_novis","0"};
-cvar_t	r_netgraph = {"r_netgraph","0"};
+cvar_t	r_norefresh = CVAR2("r_norefresh","0");
+cvar_t	r_drawentities = CVAR2("r_drawentities","1");
+cvar_t	r_drawviewmodel = CVAR2("r_drawviewmodel","1");
+cvar_t	r_speeds = CVAR2("r_speeds","0");
+cvar_t	r_fullbright = CVAR2("r_fullbright","0");
+cvar_t	r_lightmap = CVAR2("r_lightmap","0");
+cvar_t	r_shadows = CVAR2("r_shadows","0");
+cvar_t	r_mirroralpha = CVAR2("r_mirroralpha","1");
+cvar_t	r_wateralpha = CVAR2("r_wateralpha","1");
+cvar_t	r_dynamic = CVAR2("r_dynamic","1");
+cvar_t	r_novis = CVAR2("r_novis","0");
+cvar_t	r_netgraph = CVAR2("r_netgraph","0");
 
-cvar_t	gl_clear = {"gl_clear","0"};
-cvar_t	gl_cull = {"gl_cull","1"};
-cvar_t	gl_texsort = {"gl_texsort","1"};
-cvar_t	gl_smoothmodels = {"gl_smoothmodels","1"};
-cvar_t	gl_affinemodels = {"gl_affinemodels","0"};
-cvar_t	gl_polyblend = {"gl_polyblend","1"};
-cvar_t	gl_flashblend = {"gl_flashblend","1"};
-cvar_t	gl_playermip = {"gl_playermip","0"};
-cvar_t	gl_nocolors = {"gl_nocolors","0"};
-cvar_t	gl_keeptjunctions = {"gl_keeptjunctions","1"};
-cvar_t	gl_reporttjunctions = {"gl_reporttjunctions","0"};
-cvar_t	gl_finish = {"gl_finish","0"};
+cvar_t	gl_clear = CVAR2("gl_clear","0");
+cvar_t	gl_cull = CVAR2("gl_cull","1");
+cvar_t	gl_texsort = CVAR2("gl_texsort","1");
+cvar_t	gl_smoothmodels = CVAR2("gl_smoothmodels","1");
+cvar_t	gl_affinemodels = CVAR2("gl_affinemodels","0");
+cvar_t	gl_polyblend = CVAR2("gl_polyblend","1");
+cvar_t	gl_flashblend = CVAR2("gl_flashblend","1");
+cvar_t	gl_playermip = CVAR2("gl_playermip","0");
+cvar_t	gl_nocolors = CVAR2("gl_nocolors","0");
+cvar_t	gl_keeptjunctions = CVAR2("gl_keeptjunctions","1");
+cvar_t	gl_reporttjunctions = CVAR2("gl_reporttjunctions","0");
+cvar_t	gl_finish = CVAR2("gl_finish","0");
 
 extern	cvar_t	gl_ztrick;
 extern	cvar_t	scr_fov;
@@ -227,9 +227,11 @@
     GL_Bind(frame->gl_texturenum);
 
 	glEnable (GL_ALPHA_TEST);
-	glBegin (GL_QUADS);
 
-	glEnable (GL_ALPHA_TEST);
+#ifdef USE_OPENGLES
+	// !!! Need to implement this !!!
+	
+#else
 	glBegin (GL_QUADS);
 
 	glTexCoord2f (0, 1);
@@ -253,6 +255,7 @@
 	glVertex3fv (point);
 	
 	glEnd ();
+#endif
 
 	glDisable (GL_ALPHA_TEST);
 }
@@ -309,6 +312,51 @@
 		count = *order++;
 		if (!count)
 			break;		// done
+			
+#ifdef USE_OPENGLES
+		{
+			int primType;
+			float color[3*256];
+			float vertex[3*256];
+			int c;
+			float* pColor;
+			float* pVertex;
+			
+			if (count < 0)
+			{
+				count = -count;
+				primType = GL_TRIANGLE_FAN;
+			}
+			else
+				primType = GL_TRIANGLE_STRIP;
+			
+			// texture coordinates come from the draw list
+			glTexCoordPointer(2, GL_FLOAT, 0, order);
+		
+			pColor = color;
+			pVertex = vertex;
+			for(c = 0; c < count; c++)
+			{
+				// normals and vertexes come from the frame list
+				l = shadedots[verts->lightnormalindex] * shadelight;
+				*pColor++ = l;
+				*pColor++ = l;
+				*pColor++ = l;
+				*pVertex++ = verts->v[0];
+				*pVertex++ = verts->v[1];
+				*pVertex++ = verts->v[2];
+				verts++;
+			}
+			
+			glColorPointer(3, GL_FLOAT, 0, color);
+			glVertexPointer(3, GL_FLOAT, 0, vertex);
+						
+			glDrawArrays(primType, 0, count);
+			
+			order += 2 * count;
+		}
+
+#else
 		if (count < 0)
 		{
 			count = -count;
@@ -331,6 +379,7 @@
 		} while (--count);
 
 		glEnd ();
+#endif
 	}
 }
 
@@ -365,6 +414,13 @@
 		count = *order++;
 		if (!count)
 			break;		// done
+			
+#ifdef USE_OPENGLES
+
+		// !!! Implement this (based on GL_DrawAlias)
+		break;
+#else
+
 		if (count < 0)
 		{
 			count = -count;
@@ -394,6 +450,9 @@
 		} while (--count);
 
 		glEnd ();
+		
+#endif
+
 	}	
 }
 
@@ -698,9 +757,15 @@
 	diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128;
 
 	// hack the depth range to prevent view model from poking into walls
+#ifdef USE_OPENGLES
+	glDepthRangef(gldepthmin, gldepthmin + 0.3f*(gldepthmax-gldepthmin));
+	R_DrawAliasModel (currententity);
+	glDepthRangef(gldepthmin, gldepthmax);
+#else
 	glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
 	R_DrawAliasModel (currententity);
 	glDepthRange (gldepthmin, gldepthmax);
+#endif
 }
 
 
@@ -732,6 +797,9 @@
 
 	glColor4fv (v_blend);
 
+#ifdef USE_OPENGLES
+	// !!! Implement this
+#else
 	glBegin (GL_QUADS);
 
 	glVertex3f (10, 100, 100);
@@ -739,6 +807,7 @@
 	glVertex3f (10, -100, -100);
 	glVertex3f (10, 100, -100);
 	glEnd ();
+#endif
 
 	glDisable (GL_BLEND);
 	glEnable (GL_TEXTURE_2D);
@@ -835,6 +904,23 @@
 
 }
 
+#ifdef USE_OPENGLES
+
+void MYgluPerspective( float fovy, float aspect,
+		     float zNear, float zFar )
+{
+   float xmin, xmax, ymin, ymax;
+
+   ymax = zNear * tan( fovy * M_PI / 360.0f );
+   ymin = -ymax;
+
+   xmin = ymin * aspect;
+   xmax = ymax * aspect;
+
+   glFrustumf( xmin, xmax, ymin, ymax, zNear, zFar );
+}
+
+#else
 
 void MYgluPerspective( GLdouble fovy, GLdouble aspect,
 		     GLdouble zNear, GLdouble zFar )
@@ -849,7 +935,7 @@
 
    glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
 }
-
+#endif
 
 /*
 =============
@@ -920,7 +1006,11 @@
     glRotatef (-r_refdef.viewangles[1],  0, 0, 1);
     glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);
 
+#ifdef USE_OPENGLES
+	glGetIntegerv (MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, (GLint*) r_world_matrix);	
+#else
 	glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
+#endif
 
 	//
 	// set drawing parms
@@ -1020,7 +1110,11 @@
 		glDepthFunc (GL_LEQUAL);
 	}
 
+#ifdef USE_OPENGLES
+	glDepthRangef (gldepthmin, gldepthmax);
+#else
 	glDepthRange (gldepthmin, gldepthmax);
+#endif
 }
 
 #if 0 //!!! FIXME, Zoid, mirror is disabled for now
diff --git a/quake/src/QW/client/gl_rmisc.c b/quake/src/QW/client/gl_rmisc.c
old mode 100644
new mode 100755
index 96798b3..e5180db
--- a/quake/src/QW/client/gl_rmisc.c
+++ b/quake/src/QW/client/gl_rmisc.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // r_misc.c
 
 #include "quakedef.h"
@@ -88,7 +88,7 @@
 			data[y][x][3] = dottexture[x][y]*255;
 		}
 	}
-	glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+	glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 
 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
@@ -105,6 +105,9 @@
 */
 void R_Envmap_f (void)
 {
+#ifdef USE_OPENGLES
+	// Not implemented
+#else
 	byte	buffer[256*256*4];
 
 	glDrawBuffer  (GL_FRONT);
@@ -160,6 +163,7 @@
 	glDrawBuffer  (GL_BACK);
 	glReadBuffer  (GL_BACK);
 	GL_EndRendering ();
+#endif
 }
 
 /*
@@ -241,7 +245,7 @@
 	byte		*inrow;
 	unsigned	frac, fracstep;
 	player_info_t *player;
-	extern	byte		player_8bit_texels[320*200];

+	extern	byte		player_8bit_texels[320*200];
 	char s[512];
 
 	GL_DisableMultitexture();
@@ -250,8 +254,8 @@
 	if (!player->name[0])
 		return;
 
-	strcpy(s, Info_ValueForKey(player->userinfo, "skin"));

-	COM_StripExtension(s, s);

+	strcpy(s, Info_ValueForKey(player->userinfo, "skin"));
+	COM_StripExtension(s, s);
 	if (player->skin && !stricmp(s, player->skin->name))
 		player->skin = NULL;
 
@@ -337,11 +341,11 @@
 			out2 = (byte *)pixels;
 			memset(pixels, 0, sizeof(pixels));
 			fracstep = tinwidth*0x10000/scaled_width;
-			for (i=0 ; i<scaled_height ; i++, out2 += scaled_width)
+			for (i=0 ; i< (int) scaled_height ; i++, out2 += scaled_width)
 			{
 				inrow = original + inwidth*(i*tinheight/scaled_height);
 				frac = fracstep >> 1;
-				for (j=0 ; j<scaled_width ; j+=4)
+				for (j=0 ; j< (int) scaled_width ; j+=4)
 				{
 					out2[j] = translate[inrow[frac>>16]];
 					frac += fracstep;
@@ -364,11 +368,11 @@
 		out = pixels;
 		memset(pixels, 0, sizeof(pixels));
 		fracstep = tinwidth*0x10000/scaled_width;
-		for (i=0 ; i<scaled_height ; i++, out += scaled_width)
+		for (i=0 ; i< (int) scaled_height ; i++, out += scaled_width)
 		{
 			inrow = original + inwidth*(i*tinheight/scaled_height);
 			frac = fracstep >> 1;
-			for (j=0 ; j<scaled_width ; j+=4)
+			for (j=0 ; j< (int) scaled_width ; j+=4)
 			{
 				out[j] = translate32[inrow[frac>>16]];
 				frac += fracstep;
@@ -381,7 +385,7 @@
 			}
 		}
 
-		glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 
+		glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, 
 			scaled_width, scaled_height, 0, GL_RGBA, 
 			GL_UNSIGNED_BYTE, pixels);
 
@@ -444,6 +448,10 @@
 */
 void R_TimeRefresh_f (void)
 {
+#ifdef USE_OPENGLES
+	// Not implemented
+	Con_Printf("TimeRefresh not implemented.\n");
+#else
 	int			i;
 	float		start, stop, time;
 
@@ -464,6 +472,7 @@
 
 	glDrawBuffer  (GL_BACK);
 	GL_EndRendering ();
+#endif
 }
 
 void D_FlushCaches (void)
diff --git a/quake/src/QW/client/gl_rsurf.c b/quake/src/QW/client/gl_rsurf.c
old mode 100644
new mode 100755
index c50aa09..8923695
--- a/quake/src/QW/client/gl_rsurf.c
+++ b/quake/src/QW/client/gl_rsurf.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // r_surf.c: surface-related refresh code
 
 #include "quakedef.h"
@@ -324,6 +324,7 @@
 //	if ((!(s->flags & (SURF_DRAWSKY|SURF_DRAWTURB)))
 //		&& ((r_viewleaf->contents!=CONTENTS_EMPTY && (s->flags & SURF_UNDERWATER)) ||
 //		(r_viewleaf->contents==CONTENTS_EMPTY && !(s->flags & SURF_UNDERWATER))))
+#if 0
 	if (0)
 	{
 		p = s->polys;
@@ -354,6 +355,7 @@
 
 		return;
 	}
+#endif
 
 	//
 	// subdivided water surface warp
@@ -602,6 +604,9 @@
 
 	GL_DisableMultitexture();
 
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
 	glBegin (GL_TRIANGLE_FAN);
 	v = p->verts[0];
 	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
@@ -615,6 +620,7 @@
 		glVertex3fv (nv);
 	}
 	glEnd ();
+#endif
 }
 
 void DrawGLWaterPolyLightmap (glpoly_t *p)
@@ -625,6 +631,9 @@
 
 	GL_DisableMultitexture();
 
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
 	glBegin (GL_TRIANGLE_FAN);
 	v = p->verts[0];
 	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
@@ -638,6 +647,7 @@
 		glVertex3fv (nv);
 	}
 	glEnd ();
+#endif
 }
 
 /*
@@ -650,6 +660,9 @@
 	int		i;
 	float	*v;
 
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
 	glBegin (GL_POLYGON);
 	v = p->verts[0];
 	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
@@ -658,6 +671,7 @@
 		glVertex3fv (v);
 	}
 	glEnd ();
+#endif
 }
 
 
@@ -734,6 +748,9 @@
 				DrawGLWaterPolyLightmap (p);
 			else
 			{
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
 				glBegin (GL_POLYGON);
 				v = p->verts[0];
 				for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
@@ -742,6 +759,7 @@
 					glVertex3fv (v);
 				}
 				glEnd ();
+#endif
 			}
 		}
 	}
@@ -1685,7 +1703,7 @@
 		GL_Bind(lightmap_textures + i);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-		glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
+		glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
 		, BLOCK_WIDTH, BLOCK_HEIGHT, 0, 
 		gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
 	}
diff --git a/quake/src/QW/client/gl_screen.c b/quake/src/QW/client/gl_screen.c
old mode 100644
new mode 100755
index df055bd..b62ac99
--- a/quake/src/QW/client/gl_screen.c
+++ b/quake/src/QW/client/gl_screen.c
@@ -1,1188 +1,1188 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-// screen.c -- master for refresh, status bar, console, chat, notify, etc

-

-#include "quakedef.h"

-

-#include <time.h>

-

-/*

-

-background clear

-rendering

-turtle/net/ram icons

-sbar

-centerprint / slow centerprint

-notify lines

-intermission / finale overlay

-loading plaque

-console

-menu

-

-required background clears

-required update regions

-

-

-syncronous draw mode or async

-One off screen buffer, with updates either copied or xblited

-Need to double buffer?

-

-

-async draw will require the refresh area to be cleared, because it will be

-xblited, but sync draw can just ignore it.

-

-sync

-draw

-

-CenterPrint ()

-SlowPrint ()

-Screen_Update ();

-Con_Printf ();

-

-net 

-turn off messages option

-

-the refresh is allways rendered, unless the console is full screen

-

-

-console is:

-	notify lines

-	half

-	full

-	

-

-*/

-

-

-int                     glx, gly, glwidth, glheight;

-

-// only the refresh window will be updated unless these variables are flagged 

-int                     scr_copytop;

-int                     scr_copyeverything;

-

-float           scr_con_current;

-float           scr_conlines;           // lines of console to display

-

-float           oldscreensize, oldfov;

-cvar_t          scr_viewsize = {"viewsize","100", true};

-cvar_t          scr_fov = {"fov","90"}; // 10 - 170

-cvar_t          scr_conspeed = {"scr_conspeed","300"};

-cvar_t          scr_centertime = {"scr_centertime","2"};

-cvar_t          scr_showram = {"showram","1"};

-cvar_t          scr_showturtle = {"showturtle","0"};

-cvar_t          scr_showpause = {"showpause","1"};

-cvar_t          scr_printspeed = {"scr_printspeed","8"};

-cvar_t			scr_allowsnap = {"scr_allowsnap", "1"};

-cvar_t			gl_triplebuffer = {"gl_triplebuffer", "1", true };

-extern  		cvar_t  crosshair;

-

-qboolean        scr_initialized;                // ready to draw

-

-qpic_t          *scr_ram;

-qpic_t          *scr_net;

-qpic_t          *scr_turtle;

-

-int                     scr_fullupdate;

-

-int                     clearconsole;

-int                     clearnotify;

-

-int                     sb_lines;

-

-viddef_t        vid;                            // global video state

-

-vrect_t         scr_vrect;

-

-qboolean        scr_disabled_for_loading;

-qboolean        scr_drawloading;

-float           scr_disabled_time;

-

-qboolean        block_drawing;

-

-void SCR_ScreenShot_f (void);

-void SCR_RSShot_f (void);

-

-/*

-===============================================================================

-

-CENTER PRINTING

-

-===============================================================================

-*/

-

-char            scr_centerstring[1024];

-float           scr_centertime_start;   // for slow victory printing

-float           scr_centertime_off;

-int                     scr_center_lines;

-int                     scr_erase_lines;

-int                     scr_erase_center;

-

-/*

-==============

-SCR_CenterPrint

-

-Called for important messages that should stay in the center of the screen

-for a few moments

-==============

-*/

-void SCR_CenterPrint (char *str)

-{

-	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);

-	scr_centertime_off = scr_centertime.value;

-	scr_centertime_start = cl.time;

-

-// count the number of lines for centering

-	scr_center_lines = 1;

-	while (*str)

-	{

-		if (*str == '\n')

-			scr_center_lines++;

-		str++;

-	}

-}

-

-

-void SCR_DrawCenterString (void)

-{

-	char    *start;

-	int             l;

-	int             j;

-	int             x, y;

-	int             remaining;

-

-// the finale prints the characters one at a time

-	if (cl.intermission)

-		remaining = scr_printspeed.value * (cl.time - scr_centertime_start);

-	else

-		remaining = 9999;

-

-	scr_erase_center = 0;

-	start = scr_centerstring;

-

-	if (scr_center_lines <= 4)

-		y = vid.height*0.35;

-	else

-		y = 48;

-

-	do      

-	{

-	// scan the width of the line

-		for (l=0 ; l<40 ; l++)

-			if (start[l] == '\n' || !start[l])

-				break;

-		x = (vid.width - l*8)/2;

-		for (j=0 ; j<l ; j++, x+=8)

-		{

-			Draw_Character (x, y, start[j]);        

-			if (!remaining--)

-				return;

-		}

-			

-		y += 8;

-

-		while (*start && *start != '\n')

-			start++;

-

-		if (!*start)

-			break;

-		start++;                // skip the \n

-	} while (1);

-}

-

-void SCR_CheckDrawCenterString (void)

-{

-	scr_copytop = 1;

-	if (scr_center_lines > scr_erase_lines)

-		scr_erase_lines = scr_center_lines;

-

-	scr_centertime_off -= host_frametime;

-	

-	if (scr_centertime_off <= 0 && !cl.intermission)

-		return;

-	if (key_dest != key_game)

-		return;

-

-	SCR_DrawCenterString ();

-}

-

-//=============================================================================

-

-/*

-====================

-CalcFov

-====================

-*/

-float CalcFov (float fov_x, float width, float height)

-{

-        float   a;

-        float   x;

-

-        if (fov_x < 1 || fov_x > 179)

-                Sys_Error ("Bad fov: %f", fov_x);

-

-        x = width/tan(fov_x/360*M_PI);

-

-        a = atan (height/x);

-

-        a = a*360/M_PI;

-

-        return a;

-}

-

-/*

-=================

-SCR_CalcRefdef

-

-Must be called whenever vid changes

-Internal use only

-=================

-*/

-static void SCR_CalcRefdef (void)

-{

-	float           size;

-	int             h;

-	qboolean		full = false;

-

-

-	scr_fullupdate = 0;             // force a background redraw

-	vid.recalc_refdef = 0;

-

-// force the status bar to redraw

-	Sbar_Changed ();

-

-//========================================

-	

-// bound viewsize

-	if (scr_viewsize.value < 30)

-		Cvar_Set ("viewsize","30");

-	if (scr_viewsize.value > 120)

-		Cvar_Set ("viewsize","120");

-

-// bound field of view

-	if (scr_fov.value < 10)

-		Cvar_Set ("fov","10");

-	if (scr_fov.value > 170)

-		Cvar_Set ("fov","170");

-

-// intermission is always full screen   

-	if (cl.intermission)

-		size = 120;

-	else

-		size = scr_viewsize.value;

-

-	if (size >= 120)

-		sb_lines = 0;           // no status bar at all

-	else if (size >= 110)

-		sb_lines = 24;          // no inventory

-	else

-		sb_lines = 24+16+8;

-

-	if (scr_viewsize.value >= 100.0) {

-		full = true;

-		size = 100.0;

-	} else

-		size = scr_viewsize.value;

-	if (cl.intermission)

-	{

-		full = true;

-		size = 100.0;

-		sb_lines = 0;

-	}

-	size /= 100.0;

-

-	if (!cl_sbar.value && full)

-		h = vid.height;

-	else

-		h = vid.height - sb_lines;

-

-	r_refdef.vrect.width = vid.width * size;

-	if (r_refdef.vrect.width < 96)

-	{

-		size = 96.0 / r_refdef.vrect.width;

-		r_refdef.vrect.width = 96;      // min for icons

-	}

-

-	r_refdef.vrect.height = vid.height * size;

-	if (cl_sbar.value || !full) {

-  		if (r_refdef.vrect.height > vid.height - sb_lines)

-  			r_refdef.vrect.height = vid.height - sb_lines;

-	} else if (r_refdef.vrect.height > vid.height)

-			r_refdef.vrect.height = vid.height;

-	r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;

-	if (full)

-		r_refdef.vrect.y = 0;

-	else 

-		r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;

-

-	r_refdef.fov_x = scr_fov.value;

-	r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);

-

-	scr_vrect = r_refdef.vrect;

-}

-

-

-/*

-=================

-SCR_SizeUp_f

-

-Keybinding command

-=================

-*/

-void SCR_SizeUp_f (void)

-{

-	Cvar_SetValue ("viewsize",scr_viewsize.value+10);

-	vid.recalc_refdef = 1;

-}

-

-

-/*

-=================

-SCR_SizeDown_f

-

-Keybinding command

-=================

-*/

-void SCR_SizeDown_f (void)

-{

-	Cvar_SetValue ("viewsize",scr_viewsize.value-10);

-	vid.recalc_refdef = 1;

-}

-

-//============================================================================

-

-/*

-==================

-SCR_Init

-==================

-*/

-void SCR_Init (void)

-{

-	Cvar_RegisterVariable (&scr_fov);

-	Cvar_RegisterVariable (&scr_viewsize);

-	Cvar_RegisterVariable (&scr_conspeed);

-	Cvar_RegisterVariable (&scr_showram);

-	Cvar_RegisterVariable (&scr_showturtle);

-	Cvar_RegisterVariable (&scr_showpause);

-	Cvar_RegisterVariable (&scr_centertime);

-	Cvar_RegisterVariable (&scr_printspeed);

-	Cvar_RegisterVariable (&scr_allowsnap);

-	Cvar_RegisterVariable (&gl_triplebuffer);

-

-//

-// register our commands

-//

-	Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);

-	Cmd_AddCommand ("snap",SCR_RSShot_f);

-	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);

-	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);

-

-	scr_ram = Draw_PicFromWad ("ram");

-	scr_net = Draw_PicFromWad ("net");

-	scr_turtle = Draw_PicFromWad ("turtle");

-

-	scr_initialized = true;

-}

-

-

-

-/*

-==============

-SCR_DrawRam

-==============

-*/

-void SCR_DrawRam (void)

-{

-	if (!scr_showram.value)

-		return;

-

-	if (!r_cache_thrash)

-		return;

-

-	Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);

-}

-

-/*

-==============

-SCR_DrawTurtle

-==============

-*/

-void SCR_DrawTurtle (void)

-{

-	static int      count;

-	

-	if (!scr_showturtle.value)

-		return;

-

-	if (host_frametime < 0.1)

-	{

-		count = 0;

-		return;

-	}

-

-	count++;

-	if (count < 3)

-		return;

-

-	Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);

-}

-

-/*

-==============

-SCR_DrawNet

-==============

-*/

-void SCR_DrawNet (void)

-{

-	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < UPDATE_BACKUP-1)

-		return;

-	if (cls.demoplayback)

-		return;

-

-	Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);

-}

-

-void SCR_DrawFPS (void)

-{

-	extern cvar_t show_fps;

-	static double lastframetime;

-	double t;

-	extern int fps_count;

-	static lastfps;

-	int x, y;

-	char st[80];

-

-	if (!show_fps.value)

-		return;

-

-	t = Sys_DoubleTime();

-	if ((t - lastframetime) >= 1.0) {

-		lastfps = fps_count;

-		fps_count = 0;

-		lastframetime = t;

-	}

-

-	sprintf(st, "%3d FPS", lastfps);

-	x = vid.width - strlen(st) * 8 - 8;

-	y = vid.height - sb_lines - 8;

-//	Draw_TileClear(x, y, strlen(st) * 8, 8);

-	Draw_String(x, y, st);

-}

-

-

-/*

-==============

-DrawPause

-==============

-*/

-void SCR_DrawPause (void)

-{

-	qpic_t  *pic;

-

-	if (!scr_showpause.value)               // turn off for screenshots

-		return;

-

-	if (!cl.paused)

-		return;

-

-	pic = Draw_CachePic ("gfx/pause.lmp");

-	Draw_Pic ( (vid.width - pic->width)/2, 

-		(vid.height - 48 - pic->height)/2, pic);

-}

-

-

-

-/*

-==============

-SCR_DrawLoading

-==============

-*/

-void SCR_DrawLoading (void)

-{

-	qpic_t  *pic;

-

-	if (!scr_drawloading)

-		return;

-		

-	pic = Draw_CachePic ("gfx/loading.lmp");

-	Draw_Pic ( (vid.width - pic->width)/2, 

-		(vid.height - 48 - pic->height)/2, pic);

-}

-

-

-

-//=============================================================================

-

-

-/*

-==================

-SCR_SetUpToDrawConsole

-==================

-*/

-void SCR_SetUpToDrawConsole (void)

-{

-	Con_CheckResize ();

-	

-	if (scr_drawloading)

-		return;         // never a console with loading plaque

-		

-// decide on the height of the console

-	if (cls.state != ca_active)

-	{

-		scr_conlines = vid.height;              // full screen

-		scr_con_current = scr_conlines;

-	}

-	else if (key_dest == key_console)

-		scr_conlines = vid.height/2;    // half screen

-	else

-		scr_conlines = 0;                               // none visible

-	

-	if (scr_conlines < scr_con_current)

-	{

-		scr_con_current -= scr_conspeed.value*host_frametime;

-		if (scr_conlines > scr_con_current)

-			scr_con_current = scr_conlines;

-

-	}

-	else if (scr_conlines > scr_con_current)

-	{

-		scr_con_current += scr_conspeed.value*host_frametime;

-		if (scr_conlines < scr_con_current)

-			scr_con_current = scr_conlines;

-	}

-

-	if (clearconsole++ < vid.numpages)

-	{

-		Sbar_Changed ();

-	}

-	else if (clearnotify++ < vid.numpages)

-	{

-	}

-	else

-		con_notifylines = 0;

-}

-	

-/*

-==================

-SCR_DrawConsole

-==================

-*/

-void SCR_DrawConsole (void)

-{

-	if (scr_con_current)

-	{

-		scr_copyeverything = 1;

-		Con_DrawConsole (scr_con_current);

-		clearconsole = 0;

-	}

-	else

-	{

-		if (key_dest == key_game || key_dest == key_message)

-			Con_DrawNotify ();      // only draw notify in game

-	}

-}

-

-

-/* 

-============================================================================== 

- 

-						SCREEN SHOTS 

- 

-============================================================================== 

-*/ 

-

-typedef struct _TargaHeader {

-	unsigned char   id_length, colormap_type, image_type;

-	unsigned short  colormap_index, colormap_length;

-	unsigned char   colormap_size;

-	unsigned short  x_origin, y_origin, width, height;

-	unsigned char   pixel_size, attributes;

-} TargaHeader;

-

-

-/* 

-================== 

-SCR_ScreenShot_f

-================== 

-*/  

-void SCR_ScreenShot_f (void) 

-{

-	byte            *buffer;

-	char            pcxname[80]; 

-	char            checkname[MAX_OSPATH];

-	int                     i, c, temp;

-// 

-// find a file name to save it to 

-// 

-	strcpy(pcxname,"quake00.tga");

-		

-	for (i=0 ; i<=99 ; i++) 

-	{ 

-		pcxname[5] = i/10 + '0'; 

-		pcxname[6] = i%10 + '0'; 

-		sprintf (checkname, "%s/%s", com_gamedir, pcxname);

-		if (Sys_FileTime(checkname) == -1)

-			break;  // file doesn't exist

-	} 

-	if (i==100) 

-	{

-		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n"); 

-		return;

-	}

-

-

-	buffer = malloc(glwidth*glheight*3 + 18);

-	memset (buffer, 0, 18);

-	buffer[2] = 2;          // uncompressed type

-	buffer[12] = glwidth&255;

-	buffer[13] = glwidth>>8;

-	buffer[14] = glheight&255;

-	buffer[15] = glheight>>8;

-	buffer[16] = 24;        // pixel size

-

-	glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); 

-

-	// swap rgb to bgr

-	c = 18+glwidth*glheight*3;

-	for (i=18 ; i<c ; i+=3)

-	{

-		temp = buffer[i];

-		buffer[i] = buffer[i+2];

-		buffer[i+2] = temp;

-	}

-	COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );

-

-	free (buffer);

-	Con_Printf ("Wrote %s\n", pcxname);

-} 

-

-/* 

-============== 

-WritePCXfile 

-============== 

-*/ 

-void WritePCXfile (char *filename, byte *data, int width, int height,

-	int rowbytes, byte *palette, qboolean upload) 

-{

-	int		i, j, length;

-	pcx_t	*pcx;

-	byte		*pack;

-	  

-	pcx = Hunk_TempAlloc (width*height*2+1000);

-	if (pcx == NULL)

-	{

-		Con_Printf("SCR_ScreenShot_f: not enough memory\n");

-		return;

-	} 

- 

-	pcx->manufacturer = 0x0a;	// PCX id

-	pcx->version = 5;			// 256 color

- 	pcx->encoding = 1;		// uncompressed

-	pcx->bits_per_pixel = 8;		// 256 color

-	pcx->xmin = 0;

-	pcx->ymin = 0;

-	pcx->xmax = LittleShort((short)(width-1));

-	pcx->ymax = LittleShort((short)(height-1));

-	pcx->hres = LittleShort((short)width);

-	pcx->vres = LittleShort((short)height);

-	Q_memset (pcx->palette,0,sizeof(pcx->palette));

-	pcx->color_planes = 1;		// chunky image

-	pcx->bytes_per_line = LittleShort((short)width);

-	pcx->palette_type = LittleShort(2);		// not a grey scale

-	Q_memset (pcx->filler,0,sizeof(pcx->filler));

-

-// pack the image

-	pack = &pcx->data;

-

-	data += rowbytes * (height - 1);

-

-	for (i=0 ; i<height ; i++)

-	{

-		for (j=0 ; j<width ; j++)

-		{

-			if ( (*data & 0xc0) != 0xc0)

-				*pack++ = *data++;

-			else

-			{

-				*pack++ = 0xc1;

-				*pack++ = *data++;

-			}

-		}

-

-		data += rowbytes - width;

-		data -= rowbytes * 2;

-	}

-			

-// write the palette

-	*pack++ = 0x0c;	// palette ID byte

-	for (i=0 ; i<768 ; i++)

-		*pack++ = *palette++;

-		

-// write output file 

-	length = pack - (byte *)pcx;

-

-	if (upload)

-		CL_StartUpload((void *)pcx, length);

-	else

-		COM_WriteFile (filename, pcx, length);

-} 

- 

-

-

-/*

-Find closest color in the palette for named color

-*/

-int MipColor(int r, int g, int b)

-{

-	int i;

-	float dist;

-	int best;

-	float bestdist;

-	int r1, g1, b1;

-	static int lr = -1, lg = -1, lb = -1;

-	static int lastbest;

-

-	if (r == lr && g == lg && b == lb)

-		return lastbest;

-

-	bestdist = 256*256*3;

-

-	for (i = 0; i < 256; i++) {

-		r1 = host_basepal[i*3] - r;

-		g1 = host_basepal[i*3+1] - g;

-		b1 = host_basepal[i*3+2] - b;

-		dist = r1*r1 + g1*g1 + b1*b1;

-		if (dist < bestdist) {

-			bestdist = dist;

-			best = i;

-		}

-	}

-	lr = r; lg = g; lb = b;

-	lastbest = best;

-	return best;

-}

-

-// from gl_draw.c

-byte		*draw_chars;				// 8*8 graphic characters

-

-void SCR_DrawCharToSnap (int num, byte *dest, int width)

-{

-	int		row, col;

-	byte	*source;

-	int		drawline;

-	int		x;

-

-	row = num>>4;

-	col = num&15;

-	source = draw_chars + (row<<10) + (col<<3);

-

-	drawline = 8;

-

-	while (drawline--)

-	{

-		for (x=0 ; x<8 ; x++)

-			if (source[x])

-				dest[x] = source[x];

-			else

-				dest[x] = 98;

-		source += 128;

-		dest -= width;

-	}

-

-}

-

-void SCR_DrawStringToSnap (const char *s, byte *buf, int x, int y, int width)

-{

-	byte *dest;

-	const unsigned char *p;

-

-	dest = buf + ((y * width) + x);

-

-	p = (const unsigned char *)s;

-	while (*p) {

-		SCR_DrawCharToSnap(*p++, dest, width);

-		dest += 8;

-	}

-}

-

-

-/* 

-================== 

-SCR_RSShot_f

-================== 

-*/  

-void SCR_RSShot_f (void) 

-{ 

-	int     i, x, y;

-	unsigned char		*src, *dest;

-	char		pcxname[80]; 

-	char		checkname[MAX_OSPATH];

-	unsigned char		*newbuf, *srcbuf;

-	int srcrowbytes;

-	int w, h;

-	int dx, dy, dex, dey, nx;

-	int r, b, g;

-	int count;

-	float fracw, frach;

-	char st[80];

-	time_t now;

-

-	if (CL_IsUploading())

-		return; // already one pending

-

-	if (cls.state < ca_onserver)

-		return; // gotta be connected

-

-	Con_Printf("Remote screen shot requested.\n");

-

-#if 0

-// 

-// find a file name to save it to 

-// 

-	strcpy(pcxname,"mquake00.pcx");

-		

-	for (i=0 ; i<=99 ; i++) 

-	{ 

-		pcxname[6] = i/10 + '0'; 

-		pcxname[7] = i%10 + '0'; 

-		sprintf (checkname, "%s/%s", com_gamedir, pcxname);

-		if (Sys_FileTime(checkname) == -1)

-			break;	// file doesn't exist

-	} 

-	if (i==100) 

-	{

-		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX"); 

-		return;

-	}

-#endif

- 

-// 

-// save the pcx file 

-// 

-	newbuf = malloc(glheight * glwidth * 3);

-

-	glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, newbuf ); 

-

-	w = (vid.width < RSSHOT_WIDTH) ? glwidth : RSSHOT_WIDTH;

-	h = (vid.height < RSSHOT_HEIGHT) ? glheight : RSSHOT_HEIGHT;

-

-	fracw = (float)glwidth / (float)w;

-	frach = (float)glheight / (float)h;

-

-	for (y = 0; y < h; y++) {

-		dest = newbuf + (w*3 * y);

-

-		for (x = 0; x < w; x++) {

-			r = g = b = 0;

-

-			dx = x * fracw;

-			dex = (x + 1) * fracw;

-			if (dex == dx) dex++; // at least one

-			dy = y * frach;

-			dey = (y + 1) * frach;

-			if (dey == dy) dey++; // at least one

-

-			count = 0;

-			for (/* */; dy < dey; dy++) {

-				src = newbuf + (glwidth * 3 * dy) + dx * 3;

-				for (nx = dx; nx < dex; nx++) {

-					r += *src++;

-					g += *src++;

-					b += *src++;

-					count++;

-				}

-			}

-			r /= count;

-			g /= count;

-			b /= count;

-			*dest++ = r;

-			*dest++ = b;

-			*dest++ = g;

-		}

-	}

-

-	// convert to eight bit

-	for (y = 0; y < h; y++) {

-		src = newbuf + (w * 3 * y);

-		dest = newbuf + (w * y);

-

-		for (x = 0; x < w; x++) {

-			*dest++ = MipColor(src[0], src[1], src[2]);

-			src += 3;

-		}

-	}

-

-	time(&now);

-	strcpy(st, ctime(&now));

-	st[strlen(st) - 1] = 0;

-	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 1, w);

-

-	strncpy(st, cls.servername, sizeof(st));

-	st[sizeof(st) - 1] = 0;

-	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 11, w);

-

-	strncpy(st, name.string, sizeof(st));

-	st[sizeof(st) - 1] = 0;

-	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 21, w);

-

-	WritePCXfile (pcxname, newbuf, w, h, w, host_basepal, true);

-

-	free(newbuf);

-

-	Con_Printf ("Wrote %s\n", pcxname);

-} 

-

-

-

-

-//=============================================================================

-

-

-//=============================================================================

-

-char    *scr_notifystring;

-qboolean        scr_drawdialog;

-

-void SCR_DrawNotifyString (void)

-{

-	char    *start;

-	int             l;

-	int             j;

-	int             x, y;

-

-	start = scr_notifystring;

-

-	y = vid.height*0.35;

-

-	do      

-	{

-	// scan the width of the line

-		for (l=0 ; l<40 ; l++)

-			if (start[l] == '\n' || !start[l])

-				break;

-		x = (vid.width - l*8)/2;

-		for (j=0 ; j<l ; j++, x+=8)

-			Draw_Character (x, y, start[j]);        

-			

-		y += 8;

-

-		while (*start && *start != '\n')

-			start++;

-

-		if (!*start)

-			break;

-		start++;                // skip the \n

-	} while (1);

-}

-

-/*

-==================

-SCR_ModalMessage

-

-Displays a text string in the center of the screen and waits for a Y or N

-keypress.  

-==================

-*/

-int SCR_ModalMessage (char *text)

-{

-	scr_notifystring = text;

- 

-// draw a fresh screen

-	scr_fullupdate = 0;

-	scr_drawdialog = true;

-	SCR_UpdateScreen ();

-	scr_drawdialog = false;

-	

-	S_ClearBuffer ();               // so dma doesn't loop current sound

-

-	do

-	{

-		key_count = -1;         // wait for a key down and up

-		Sys_SendKeyEvents ();

-	} while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);

-

-	scr_fullupdate = 0;

-	SCR_UpdateScreen ();

-

-	return key_lastpress == 'y';

-}

-

-

-//=============================================================================

-

-/*

-===============

-SCR_BringDownConsole

-

-Brings the console down and fades the palettes back to normal

-================

-*/

-void SCR_BringDownConsole (void)

-{

-	int             i;

-	

-	scr_centertime_off = 0;

-	

-	for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)

-		SCR_UpdateScreen ();

-

-	cl.cshifts[0].percent = 0;              // no area contents palette on next frame

-	VID_SetPalette (host_basepal);

-}

-

-void SCR_TileClear (void)

-{

-	if (r_refdef.vrect.x > 0) {

-		// left

-		Draw_TileClear (0, 0, r_refdef.vrect.x, vid.height - sb_lines);

-		// right

-		Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0, 

-			vid.width - r_refdef.vrect.x + r_refdef.vrect.width, 

-			vid.height - sb_lines);

-	}

-	if (r_refdef.vrect.y > 0) {

-		// top

-		Draw_TileClear (r_refdef.vrect.x, 0, 

-			r_refdef.vrect.x + r_refdef.vrect.width, 

-			r_refdef.vrect.y);

-		// bottom

-		Draw_TileClear (r_refdef.vrect.x,

-			r_refdef.vrect.y + r_refdef.vrect.height, 

-			r_refdef.vrect.width, 

-			vid.height - sb_lines - 

-			(r_refdef.vrect.height + r_refdef.vrect.y));

-	}

-}

-

-float oldsbar = 0;

-

-/*

-==================

-SCR_UpdateScreen

-

-This is called every frame, and can also be called explicitly to flush

-text to the screen.

-

-WARNING: be very careful calling this from elsewhere, because the refresh

-needs almost the entire 256k of stack space!

-==================

-*/

-void SCR_UpdateScreen (void)

-{

-	if (block_drawing)

-		return;

-

-	vid.numpages = 2 + gl_triplebuffer.value;

-

-	scr_copytop = 0;

-	scr_copyeverything = 0;

-

-	if (scr_disabled_for_loading)

-	{

-		if (realtime - scr_disabled_time > 60)

-		{

-			scr_disabled_for_loading = false;

-			Con_Printf ("load failed.\n");

-		}

-		else

-			return;

-	}

-

-	if (!scr_initialized || !con_initialized)

-		return;                         // not initialized yet

-

-

-	if (oldsbar != cl_sbar.value) {

-		oldsbar = cl_sbar.value;

-		vid.recalc_refdef = true;

-	}

-

-	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);

-	

-	//

-	// determine size of refresh window

-	//

-	if (oldfov != scr_fov.value)

-	{

-		oldfov = scr_fov.value;

-		vid.recalc_refdef = true;

-	}

-

-	if (vid.recalc_refdef)

-		SCR_CalcRefdef ();

-

-//

-// do 3D refresh drawing, and then update the screen

-//

-	SCR_SetUpToDrawConsole ();

-	

-	V_RenderView ();

-

-	GL_Set2D ();

-

-	//

-	// draw any areas not covered by the refresh

-	//

-	SCR_TileClear ();

-

-	if (r_netgraph.value)

-		R_NetGraph ();

-

-	if (scr_drawdialog)

-	{

-		Sbar_Draw ();

-		Draw_FadeScreen ();

-		SCR_DrawNotifyString ();

-		scr_copyeverything = true;

-	}

-	else if (scr_drawloading)

-	{

-		SCR_DrawLoading ();

-		Sbar_Draw ();

-	}

-	else if (cl.intermission == 1 && key_dest == key_game)

-	{

-		Sbar_IntermissionOverlay ();

-	}

-	else if (cl.intermission == 2 && key_dest == key_game)

-	{

-		Sbar_FinaleOverlay ();

-		SCR_CheckDrawCenterString ();

-	}

-	else

-	{

-		if (crosshair.value)

-			Draw_Crosshair();

-		

-		SCR_DrawRam ();

-		SCR_DrawNet ();

-		SCR_DrawFPS ();

-		SCR_DrawTurtle ();

-		SCR_DrawPause ();

-		SCR_CheckDrawCenterString ();

-		Sbar_Draw ();

-		SCR_DrawConsole ();     

-		M_Draw ();

-	}

-

-	V_UpdatePalette ();

-

-	GL_EndRendering ();

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+// screen.c -- master for refresh, status bar, console, chat, notify, etc
+
+#include "quakedef.h"
+
+#include <time.h>
+
+/*
+
+background clear
+rendering
+turtle/net/ram icons
+sbar
+centerprint / slow centerprint
+notify lines
+intermission / finale overlay
+loading plaque
+console
+menu
+
+required background clears
+required update regions
+
+
+syncronous draw mode or async
+One off screen buffer, with updates either copied or xblited
+Need to double buffer?
+
+
+async draw will require the refresh area to be cleared, because it will be
+xblited, but sync draw can just ignore it.
+
+sync
+draw
+
+CenterPrint ()
+SlowPrint ()
+Screen_Update ();
+Con_Printf ();
+
+net 
+turn off messages option
+
+the refresh is allways rendered, unless the console is full screen
+
+
+console is:
+	notify lines
+	half
+	full
+	
+
+*/
+
+
+int                     glx, gly, glwidth, glheight;
+
+// only the refresh window will be updated unless these variables are flagged 
+int                     scr_copytop;
+int                     scr_copyeverything;
+
+float           scr_con_current;
+float           scr_conlines;           // lines of console to display
+
+float           oldscreensize, oldfov;
+cvar_t          scr_viewsize = CVAR3("viewsize","100", true);
+cvar_t          scr_fov = CVAR2("fov","90"); // 10 - 170
+cvar_t          scr_conspeed = CVAR2("scr_conspeed","300");
+cvar_t          scr_centertime = CVAR2("scr_centertime","2");
+cvar_t          scr_showram = CVAR2("showram","1");
+cvar_t          scr_showturtle = CVAR2("showturtle","0");
+cvar_t          scr_showpause = CVAR2("showpause","1");
+cvar_t          scr_printspeed = CVAR2("scr_printspeed","8");
+cvar_t			scr_allowsnap = CVAR2("scr_allowsnap", "1");
+cvar_t			gl_triplebuffer = CVAR3("gl_triplebuffer", "1", true );
+extern  		cvar_t  crosshair;
+
+qboolean        scr_initialized;                // ready to draw
+
+qpic_t          *scr_ram;
+qpic_t          *scr_net;
+qpic_t          *scr_turtle;
+
+int                     scr_fullupdate;
+
+int                     clearconsole;
+int                     clearnotify;
+
+int                     sb_lines;
+
+viddef_t        vid;                            // global video state
+
+vrect_t         scr_vrect;
+
+qboolean        scr_disabled_for_loading;
+qboolean        scr_drawloading;
+float           scr_disabled_time;
+
+qboolean        block_drawing;
+
+void SCR_ScreenShot_f (void);
+void SCR_RSShot_f (void);
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+char            scr_centerstring[1024];
+float           scr_centertime_start;   // for slow victory printing
+float           scr_centertime_off;
+int                     scr_center_lines;
+int                     scr_erase_lines;
+int                     scr_erase_center;
+
+/*
+==============
+SCR_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void SCR_CenterPrint (char *str)
+{
+	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
+	scr_centertime_off = scr_centertime.value;
+	scr_centertime_start = cl.time;
+
+// count the number of lines for centering
+	scr_center_lines = 1;
+	while (*str)
+	{
+		if (*str == '\n')
+			scr_center_lines++;
+		str++;
+	}
+}
+
+
+void SCR_DrawCenterString (void)
+{
+	char    *start;
+	int             l;
+	int             j;
+	int             x, y;
+	int             remaining;
+
+// the finale prints the characters one at a time
+	if (cl.intermission)
+		remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
+	else
+		remaining = 9999;
+
+	scr_erase_center = 0;
+	start = scr_centerstring;
+
+	if (scr_center_lines <= 4)
+		y = vid.height*0.35;
+	else
+		y = 48;
+
+	do      
+	{
+	// scan the width of the line
+		for (l=0 ; l<40 ; l++)
+			if (start[l] == '\n' || !start[l])
+				break;
+		x = (vid.width - l*8)/2;
+		for (j=0 ; j<l ; j++, x+=8)
+		{
+			Draw_Character (x, y, start[j]);        
+			if (!remaining--)
+				return;
+		}
+			
+		y += 8;
+
+		while (*start && *start != '\n')
+			start++;
+
+		if (!*start)
+			break;
+		start++;                // skip the \n
+	} while (1);
+}
+
+void SCR_CheckDrawCenterString (void)
+{
+	scr_copytop = 1;
+	if (scr_center_lines > scr_erase_lines)
+		scr_erase_lines = scr_center_lines;
+
+	scr_centertime_off -= host_frametime;
+	
+	if (scr_centertime_off <= 0 && !cl.intermission)
+		return;
+	if (key_dest != key_game)
+		return;
+
+	SCR_DrawCenterString ();
+}
+
+//=============================================================================
+
+/*
+====================
+CalcFov
+====================
+*/
+float CalcFov (float fov_x, float width, float height)
+{
+        float   a;
+        float   x;
+
+        if (fov_x < 1 || fov_x > 179)
+                Sys_Error ("Bad fov: %f", fov_x);
+
+        x = width/tan(fov_x/360*M_PI);
+
+        a = atan (height/x);
+
+        a = a*360/M_PI;
+
+        return a;
+}
+
+/*
+=================
+SCR_CalcRefdef
+
+Must be called whenever vid changes
+Internal use only
+=================
+*/
+static void SCR_CalcRefdef (void)
+{
+	float           size;
+	int             h;
+	qboolean		full = false;
+
+
+	scr_fullupdate = 0;             // force a background redraw
+	vid.recalc_refdef = 0;
+
+// force the status bar to redraw
+	Sbar_Changed ();
+
+//========================================
+	
+// bound viewsize
+	if (scr_viewsize.value < 30)
+		Cvar_Set ("viewsize","30");
+	if (scr_viewsize.value > 120)
+		Cvar_Set ("viewsize","120");
+
+// bound field of view
+	if (scr_fov.value < 10)
+		Cvar_Set ("fov","10");
+	if (scr_fov.value > 170)
+		Cvar_Set ("fov","170");
+
+// intermission is always full screen   
+	if (cl.intermission)
+		size = 120;
+	else
+		size = scr_viewsize.value;
+
+	if (size >= 120)
+		sb_lines = 0;           // no status bar at all
+	else if (size >= 110)
+		sb_lines = 24;          // no inventory
+	else
+		sb_lines = 24+16+8;
+
+	if (scr_viewsize.value >= 100.0) {
+		full = true;
+		size = 100.0;
+	} else
+		size = scr_viewsize.value;
+	if (cl.intermission)
+	{
+		full = true;
+		size = 100.0;
+		sb_lines = 0;
+	}
+	size /= 100.0;
+
+	if (!cl_sbar.value && full)
+		h = vid.height;
+	else
+		h = vid.height - sb_lines;
+
+	r_refdef.vrect.width = vid.width * size;
+	if (r_refdef.vrect.width < 96)
+	{
+		size = 96.0 / r_refdef.vrect.width;
+		r_refdef.vrect.width = 96;      // min for icons
+	}
+
+	r_refdef.vrect.height = vid.height * size;
+	if (cl_sbar.value || !full) {
+  		if (r_refdef.vrect.height > (int) (vid.height - sb_lines))
+  			r_refdef.vrect.height = vid.height - sb_lines;
+	} else if (r_refdef.vrect.height > (int) vid.height)
+			r_refdef.vrect.height = vid.height;
+	r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
+	if (full)
+		r_refdef.vrect.y = 0;
+	else 
+		r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
+
+	r_refdef.fov_x = scr_fov.value;
+	r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
+
+	scr_vrect = r_refdef.vrect;
+}
+
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize.value+10);
+	vid.recalc_refdef = 1;
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize.value-10);
+	vid.recalc_refdef = 1;
+}
+
+//============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+	Cvar_RegisterVariable (&scr_fov);
+	Cvar_RegisterVariable (&scr_viewsize);
+	Cvar_RegisterVariable (&scr_conspeed);
+	Cvar_RegisterVariable (&scr_showram);
+	Cvar_RegisterVariable (&scr_showturtle);
+	Cvar_RegisterVariable (&scr_showpause);
+	Cvar_RegisterVariable (&scr_centertime);
+	Cvar_RegisterVariable (&scr_printspeed);
+	Cvar_RegisterVariable (&scr_allowsnap);
+	Cvar_RegisterVariable (&gl_triplebuffer);
+
+//
+// register our commands
+//
+	Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
+	Cmd_AddCommand ("snap",SCR_RSShot_f);
+	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+
+	scr_ram = Draw_PicFromWad ("ram");
+	scr_net = Draw_PicFromWad ("net");
+	scr_turtle = Draw_PicFromWad ("turtle");
+
+	scr_initialized = true;
+}
+
+
+
+/*
+==============
+SCR_DrawRam
+==============
+*/
+void SCR_DrawRam (void)
+{
+	if (!scr_showram.value)
+		return;
+
+	if (!r_cache_thrash)
+		return;
+
+	Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
+}
+
+/*
+==============
+SCR_DrawTurtle
+==============
+*/
+void SCR_DrawTurtle (void)
+{
+	static int      count;
+	
+	if (!scr_showturtle.value)
+		return;
+
+	if (host_frametime < 0.1)
+	{
+		count = 0;
+		return;
+	}
+
+	count++;
+	if (count < 3)
+		return;
+
+	Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
+}
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < UPDATE_BACKUP-1)
+		return;
+	if (cls.demoplayback)
+		return;
+
+	Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
+}
+
+void SCR_DrawFPS (void)
+{
+	extern cvar_t show_fps;
+	static double lastframetime;
+	double t;
+	extern int fps_count;
+	static int lastfps;
+	int x, y;
+	char st[80];
+
+	if (!show_fps.value)
+		return;
+
+	t = Sys_DoubleTime();
+	if ((t - lastframetime) >= 1.0) {
+		lastfps = fps_count;
+		fps_count = 0;
+		lastframetime = t;
+	}
+
+	sprintf(st, "%3d FPS", lastfps);
+	x = vid.width - strlen(st) * 8 - 8;
+	y = vid.height - sb_lines - 8;
+//	Draw_TileClear(x, y, strlen(st) * 8, 8);
+	Draw_String(x, y, st);
+}
+
+
+/*
+==============
+DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+	qpic_t  *pic;
+
+	if (!scr_showpause.value)               // turn off for screenshots
+		return;
+
+	if (!cl.paused)
+		return;
+
+	pic = Draw_CachePic ("gfx/pause.lmp");
+	Draw_Pic ( (vid.width - pic->width)/2, 
+		(vid.height - 48 - pic->height)/2, pic);
+}
+
+
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+void SCR_DrawLoading (void)
+{
+	qpic_t  *pic;
+
+	if (!scr_drawloading)
+		return;
+		
+	pic = Draw_CachePic ("gfx/loading.lmp");
+	Draw_Pic ( (vid.width - pic->width)/2, 
+		(vid.height - 48 - pic->height)/2, pic);
+}
+
+
+
+//=============================================================================
+
+
+/*
+==================
+SCR_SetUpToDrawConsole
+==================
+*/
+void SCR_SetUpToDrawConsole (void)
+{
+	Con_CheckResize ();
+	
+	if (scr_drawloading)
+		return;         // never a console with loading plaque
+		
+// decide on the height of the console
+	if (cls.state != ca_active)
+	{
+		scr_conlines = vid.height;              // full screen
+		scr_con_current = scr_conlines;
+	}
+	else if (key_dest == key_console)
+		scr_conlines = vid.height/2;    // half screen
+	else
+		scr_conlines = 0;                               // none visible
+	
+	if (scr_conlines < scr_con_current)
+	{
+		scr_con_current -= scr_conspeed.value*host_frametime;
+		if (scr_conlines > scr_con_current)
+			scr_con_current = scr_conlines;
+
+	}
+	else if (scr_conlines > scr_con_current)
+	{
+		scr_con_current += scr_conspeed.value*host_frametime;
+		if (scr_conlines < scr_con_current)
+			scr_con_current = scr_conlines;
+	}
+
+	if (clearconsole++ < vid.numpages)
+	{
+		Sbar_Changed ();
+	}
+	else if (clearnotify++ < vid.numpages)
+	{
+	}
+	else
+		con_notifylines = 0;
+}
+	
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+	if (scr_con_current)
+	{
+		scr_copyeverything = 1;
+		Con_DrawConsole (scr_con_current);
+		clearconsole = 0;
+	}
+	else
+	{
+		if (key_dest == key_game || key_dest == key_message)
+			Con_DrawNotify ();      // only draw notify in game
+	}
+}
+
+
+/* 
+============================================================================== 
+ 
+						SCREEN SHOTS 
+ 
+============================================================================== 
+*/ 
+
+typedef struct _TargaHeader {
+	unsigned char   id_length, colormap_type, image_type;
+	unsigned short  colormap_index, colormap_length;
+	unsigned char   colormap_size;
+	unsigned short  x_origin, y_origin, width, height;
+	unsigned char   pixel_size, attributes;
+} TargaHeader;
+
+
+/* 
+================== 
+SCR_ScreenShot_f
+================== 
+*/  
+void SCR_ScreenShot_f (void) 
+{
+	byte            *buffer;
+	char            pcxname[80]; 
+	char            checkname[MAX_OSPATH];
+	int                     i, c, temp;
+// 
+// find a file name to save it to 
+// 
+	strcpy(pcxname,"quake00.tga");
+		
+	for (i=0 ; i<=99 ; i++) 
+	{ 
+		pcxname[5] = i/10 + '0'; 
+		pcxname[6] = i%10 + '0'; 
+		sprintf (checkname, "%s/%s", com_gamedir, pcxname);
+		if (Sys_FileTime(checkname) == -1)
+			break;  // file doesn't exist
+	} 
+	if (i==100) 
+	{
+		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n"); 
+		return;
+	}
+
+
+	buffer = malloc(glwidth*glheight*3 + 18);
+	memset (buffer, 0, 18);
+	buffer[2] = 2;          // uncompressed type
+	buffer[12] = glwidth&255;
+	buffer[13] = glwidth>>8;
+	buffer[14] = glheight&255;
+	buffer[15] = glheight>>8;
+	buffer[16] = 24;        // pixel size
+
+	glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); 
+
+	// swap rgb to bgr
+	c = 18+glwidth*glheight*3;
+	for (i=18 ; i<c ; i+=3)
+	{
+		temp = buffer[i];
+		buffer[i] = buffer[i+2];
+		buffer[i+2] = temp;
+	}
+	COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );
+
+	free (buffer);
+	Con_Printf ("Wrote %s\n", pcxname);
+} 
+
+/* 
+============== 
+WritePCXfile 
+============== 
+*/ 
+void WritePCXfile (char *filename, byte *data, int width, int height,
+	int rowbytes, byte *palette, qboolean upload) 
+{
+	int		i, j, length;
+	pcx_t	*pcx;
+	byte		*pack;
+	  
+	pcx = Hunk_TempAlloc (width*height*2+1000);
+	if (pcx == NULL)
+	{
+		Con_Printf("SCR_ScreenShot_f: not enough memory\n");
+		return;
+	} 
+ 
+	pcx->manufacturer = 0x0a;	// PCX id
+	pcx->version = 5;			// 256 color
+ 	pcx->encoding = 1;		// uncompressed
+	pcx->bits_per_pixel = 8;		// 256 color
+	pcx->xmin = 0;
+	pcx->ymin = 0;
+	pcx->xmax = LittleShort((short)(width-1));
+	pcx->ymax = LittleShort((short)(height-1));
+	pcx->hres = LittleShort((short)width);
+	pcx->vres = LittleShort((short)height);
+	Q_memset (pcx->palette,0,sizeof(pcx->palette));
+	pcx->color_planes = 1;		// chunky image
+	pcx->bytes_per_line = LittleShort((short)width);
+	pcx->palette_type = LittleShort(2);		// not a grey scale
+	Q_memset (pcx->filler,0,sizeof(pcx->filler));
+
+// pack the image
+	pack = &pcx->data;
+
+	data += rowbytes * (height - 1);
+
+	for (i=0 ; i<height ; i++)
+	{
+		for (j=0 ; j<width ; j++)
+		{
+			if ( (*data & 0xc0) != 0xc0)
+				*pack++ = *data++;
+			else
+			{
+				*pack++ = 0xc1;
+				*pack++ = *data++;
+			}
+		}
+
+		data += rowbytes - width;
+		data -= rowbytes * 2;
+	}
+			
+// write the palette
+	*pack++ = 0x0c;	// palette ID byte
+	for (i=0 ; i<768 ; i++)
+		*pack++ = *palette++;
+		
+// write output file 
+	length = pack - (byte *)pcx;
+
+	if (upload)
+		CL_StartUpload((void *)pcx, length);
+	else
+		COM_WriteFile (filename, pcx, length);
+} 
+ 
+
+
+/*
+Find closest color in the palette for named color
+*/
+int MipColor(int r, int g, int b)
+{
+	int i;
+	float dist;
+	int best = 0;
+	float bestdist;
+	int r1, g1, b1;
+	static int lr = -1, lg = -1, lb = -1;
+	static int lastbest;
+
+	if (r == lr && g == lg && b == lb)
+		return lastbest;
+
+	bestdist = 256*256*3;
+
+	for (i = 0; i < 256; i++) {
+		r1 = host_basepal[i*3] - r;
+		g1 = host_basepal[i*3+1] - g;
+		b1 = host_basepal[i*3+2] - b;
+		dist = r1*r1 + g1*g1 + b1*b1;
+		if (dist < bestdist) {
+			bestdist = dist;
+			best = i;
+		}
+	}
+	lr = r; lg = g; lb = b;
+	lastbest = best;
+	return best;
+}
+
+// from gl_draw.c
+byte		*draw_chars;				// 8*8 graphic characters
+
+void SCR_DrawCharToSnap (int num, byte *dest, int width)
+{
+	int		row, col;
+	byte	*source;
+	int		drawline;
+	int		x;
+
+	row = num>>4;
+	col = num&15;
+	source = draw_chars + (row<<10) + (col<<3);
+
+	drawline = 8;
+
+	while (drawline--)
+	{
+		for (x=0 ; x<8 ; x++)
+			if (source[x])
+				dest[x] = source[x];
+			else
+				dest[x] = 98;
+		source += 128;
+		dest -= width;
+	}
+
+}
+
+void SCR_DrawStringToSnap (const char *s, byte *buf, int x, int y, int width)
+{
+	byte *dest;
+	const unsigned char *p;
+
+	dest = buf + ((y * width) + x);
+
+	p = (const unsigned char *)s;
+	while (*p) {
+		SCR_DrawCharToSnap(*p++, dest, width);
+		dest += 8;
+	}
+}
+
+
+/* 
+================== 
+SCR_RSShot_f
+================== 
+*/  
+void SCR_RSShot_f (void) 
+{ 
+	int     i, x, y;
+	unsigned char		*src, *dest;
+	char		pcxname[80]; 
+	char		checkname[MAX_OSPATH];
+	unsigned char		*newbuf, *srcbuf;
+	int srcrowbytes;
+	int w, h;
+	int dx, dy, dex, dey, nx;
+	int r, b, g;
+	int count;
+	float fracw, frach;
+	char st[80];
+	time_t now;
+
+	if (CL_IsUploading())
+		return; // already one pending
+
+	if (cls.state < ca_onserver)
+		return; // gotta be connected
+
+	Con_Printf("Remote screen shot requested.\n");
+
+#if 0
+// 
+// find a file name to save it to 
+// 
+	strcpy(pcxname,"mquake00.pcx");
+		
+	for (i=0 ; i<=99 ; i++) 
+	{ 
+		pcxname[6] = i/10 + '0'; 
+		pcxname[7] = i%10 + '0'; 
+		sprintf (checkname, "%s/%s", com_gamedir, pcxname);
+		if (Sys_FileTime(checkname) == -1)
+			break;	// file doesn't exist
+	} 
+	if (i==100) 
+	{
+		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX"); 
+		return;
+	}
+#endif
+ 
+// 
+// save the pcx file 
+// 
+	newbuf = malloc(glheight * glwidth * 3);
+
+	glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, newbuf ); 
+
+	w = (vid.width < RSSHOT_WIDTH) ? glwidth : RSSHOT_WIDTH;
+	h = (vid.height < RSSHOT_HEIGHT) ? glheight : RSSHOT_HEIGHT;
+
+	fracw = (float)glwidth / (float)w;
+	frach = (float)glheight / (float)h;
+
+	for (y = 0; y < h; y++) {
+		dest = newbuf + (w*3 * y);
+
+		for (x = 0; x < w; x++) {
+			r = g = b = 0;
+
+			dx = x * fracw;
+			dex = (x + 1) * fracw;
+			if (dex == dx) dex++; // at least one
+			dy = y * frach;
+			dey = (y + 1) * frach;
+			if (dey == dy) dey++; // at least one
+
+			count = 0;
+			for (/* */; dy < dey; dy++) {
+				src = newbuf + (glwidth * 3 * dy) + dx * 3;
+				for (nx = dx; nx < dex; nx++) {
+					r += *src++;
+					g += *src++;
+					b += *src++;
+					count++;
+				}
+			}
+			r /= count;
+			g /= count;
+			b /= count;
+			*dest++ = r;
+			*dest++ = b;
+			*dest++ = g;
+		}
+	}
+
+	// convert to eight bit
+	for (y = 0; y < h; y++) {
+		src = newbuf + (w * 3 * y);
+		dest = newbuf + (w * y);
+
+		for (x = 0; x < w; x++) {
+			*dest++ = MipColor(src[0], src[1], src[2]);
+			src += 3;
+		}
+	}
+
+	time(&now);
+	strcpy(st, ctime(&now));
+	st[strlen(st) - 1] = 0;
+	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 1, w);
+
+	strncpy(st, cls.servername, sizeof(st));
+	st[sizeof(st) - 1] = 0;
+	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 11, w);
+
+	strncpy(st, name.string, sizeof(st));
+	st[sizeof(st) - 1] = 0;
+	SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 21, w);
+
+	WritePCXfile (pcxname, newbuf, w, h, w, host_basepal, true);
+
+	free(newbuf);
+
+	Con_Printf ("Wrote %s\n", pcxname);
+} 
+
+
+
+
+//=============================================================================
+
+
+//=============================================================================
+
+char    *scr_notifystring;
+qboolean        scr_drawdialog;
+
+void SCR_DrawNotifyString (void)
+{
+	char    *start;
+	int             l;
+	int             j;
+	int             x, y;
+
+	start = scr_notifystring;
+
+	y = vid.height*0.35;
+
+	do      
+	{
+	// scan the width of the line
+		for (l=0 ; l<40 ; l++)
+			if (start[l] == '\n' || !start[l])
+				break;
+		x = (vid.width - l*8)/2;
+		for (j=0 ; j<l ; j++, x+=8)
+			Draw_Character (x, y, start[j]);        
+			
+		y += 8;
+
+		while (*start && *start != '\n')
+			start++;
+
+		if (!*start)
+			break;
+		start++;                // skip the \n
+	} while (1);
+}
+
+/*
+==================
+SCR_ModalMessage
+
+Displays a text string in the center of the screen and waits for a Y or N
+keypress.  
+==================
+*/
+int SCR_ModalMessage (char *text)
+{
+	scr_notifystring = text;
+ 
+// draw a fresh screen
+	scr_fullupdate = 0;
+	scr_drawdialog = true;
+	SCR_UpdateScreen ();
+	scr_drawdialog = false;
+	
+	S_ClearBuffer ();               // so dma doesn't loop current sound
+
+	do
+	{
+		key_count = -1;         // wait for a key down and up
+		Sys_SendKeyEvents ();
+	} while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
+
+	scr_fullupdate = 0;
+	SCR_UpdateScreen ();
+
+	return key_lastpress == 'y';
+}
+
+
+//=============================================================================
+
+/*
+===============
+SCR_BringDownConsole
+
+Brings the console down and fades the palettes back to normal
+================
+*/
+void SCR_BringDownConsole (void)
+{
+	int             i;
+	
+	scr_centertime_off = 0;
+	
+	for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
+		SCR_UpdateScreen ();
+
+	cl.cshifts[0].percent = 0;              // no area contents palette on next frame
+	VID_SetPalette (host_basepal);
+}
+
+void SCR_TileClear (void)
+{
+	if (r_refdef.vrect.x > 0) {
+		// left
+		Draw_TileClear (0, 0, r_refdef.vrect.x, vid.height - sb_lines);
+		// right
+		Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0, 
+			vid.width - r_refdef.vrect.x + r_refdef.vrect.width, 
+			vid.height - sb_lines);
+	}
+	if (r_refdef.vrect.y > 0) {
+		// top
+		Draw_TileClear (r_refdef.vrect.x, 0, 
+			r_refdef.vrect.x + r_refdef.vrect.width, 
+			r_refdef.vrect.y);
+		// bottom
+		Draw_TileClear (r_refdef.vrect.x,
+			r_refdef.vrect.y + r_refdef.vrect.height, 
+			r_refdef.vrect.width, 
+			vid.height - sb_lines - 
+			(r_refdef.vrect.height + r_refdef.vrect.y));
+	}
+}
+
+float oldsbar = 0;
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+
+WARNING: be very careful calling this from elsewhere, because the refresh
+needs almost the entire 256k of stack space!
+==================
+*/
+void SCR_UpdateScreen (void)
+{
+	if (block_drawing)
+		return;
+
+	vid.numpages = 2 + gl_triplebuffer.value;
+
+	scr_copytop = 0;
+	scr_copyeverything = 0;
+
+	if (scr_disabled_for_loading)
+	{
+		if (realtime - scr_disabled_time > 60)
+		{
+			scr_disabled_for_loading = false;
+			Con_Printf ("load failed.\n");
+		}
+		else
+			return;
+	}
+
+	if (!scr_initialized || !con_initialized)
+		return;                         // not initialized yet
+
+
+	if (oldsbar != cl_sbar.value) {
+		oldsbar = cl_sbar.value;
+		vid.recalc_refdef = true;
+	}
+
+	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
+	
+	//
+	// determine size of refresh window
+	//
+	if (oldfov != scr_fov.value)
+	{
+		oldfov = scr_fov.value;
+		vid.recalc_refdef = true;
+	}
+
+	if (vid.recalc_refdef)
+		SCR_CalcRefdef ();
+
+//
+// do 3D refresh drawing, and then update the screen
+//
+	SCR_SetUpToDrawConsole ();
+	
+	V_RenderView ();
+
+	GL_Set2D ();
+
+	//
+	// draw any areas not covered by the refresh
+	//
+	SCR_TileClear ();
+
+	if (r_netgraph.value)
+		R_NetGraph ();
+
+	if (scr_drawdialog)
+	{
+		Sbar_Draw ();
+		Draw_FadeScreen ();
+		SCR_DrawNotifyString ();
+		scr_copyeverything = true;
+	}
+	else if (scr_drawloading)
+	{
+		SCR_DrawLoading ();
+		Sbar_Draw ();
+	}
+	else if (cl.intermission == 1 && key_dest == key_game)
+	{
+		Sbar_IntermissionOverlay ();
+	}
+	else if (cl.intermission == 2 && key_dest == key_game)
+	{
+		Sbar_FinaleOverlay ();
+		SCR_CheckDrawCenterString ();
+	}
+	else
+	{
+		if (crosshair.value)
+			Draw_Crosshair();
+		
+		SCR_DrawRam ();
+		SCR_DrawNet ();
+		SCR_DrawFPS ();
+		SCR_DrawTurtle ();
+		SCR_DrawPause ();
+		SCR_CheckDrawCenterString ();
+		Sbar_Draw ();
+		SCR_DrawConsole ();     
+		M_Draw ();
+	}
+
+	V_UpdatePalette ();
+
+	GL_EndRendering ();
+}
diff --git a/quake/src/QW/client/gl_test.c b/quake/src/QW/client/gl_test.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_vidandroid.c b/quake/src/QW/client/gl_vidandroid.c
new file mode 100755
index 0000000..95dc37a
--- /dev/null
+++ b/quake/src/QW/client/gl_vidandroid.c
@@ -0,0 +1,337 @@
+/*
+Copyright (C) 2007 The Android Open Source Project
+
+*/
+
+#include "quakedef.h"
+
+unsigned short	d_8to16table[256];
+unsigned	d_8to24table[256];
+unsigned char d_15to8table[65536];
+
+int scr_width, scr_height;
+
+cvar_t	_windowed_mouse = CVAR3("_windowed_mouse","0", true);
+
+/*-----------------------------------------------------------------------*/
+
+//int		texture_mode = GL_NEAREST;
+//int		texture_mode = GL_NEAREST_MIPMAP_NEAREST;
+//int		texture_mode = GL_NEAREST_MIPMAP_LINEAR;
+int		texture_mode = GL_LINEAR;
+//int		texture_mode = GL_LINEAR_MIPMAP_NEAREST;
+//int		texture_mode = GL_LINEAR_MIPMAP_LINEAR;
+
+int		texture_extension_number = 1;
+
+float		gldepthmin, gldepthmax;
+
+cvar_t	gl_ztrick = CVAR2("gl_ztrick","1");
+
+const char *gl_vendor;
+const char *gl_renderer;
+const char *gl_version;
+const char *gl_extensions;
+
+qboolean is8bit = false;
+qboolean gl_mtexable = false;
+
+/*-----------------------------------------------------------------------*/
+void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
+{
+}
+
+void D_EndDirectRect (int x, int y, int width, int height)
+{
+}
+
+void VID_Shutdown(void)
+{
+}
+
+
+void VID_ShiftPalette(unsigned char *p)
+{
+//	VID_SetPalette(p);
+}
+
+void	VID_SetPalette (unsigned char *palette)
+{
+	byte	*pal;
+	unsigned r,g,b;
+	unsigned v;
+	int     r1,g1,b1;
+	int		k;
+	unsigned short i;
+	unsigned	*table;
+	FILE *f;
+	char s[255];
+	float dist, bestdist;
+	static qboolean palflag = false;
+
+//
+// 8 8 8 encoding
+//
+	Con_Printf("Converting 8to24\n");
+
+	pal = palette;
+	table = d_8to24table;
+	for (i=0 ; i<256 ; i++)
+	{
+		r = pal[0];
+		g = pal[1];
+		b = pal[2];
+		pal += 3;
+		
+//		v = (255<<24) + (r<<16) + (g<<8) + (b<<0);
+//		v = (255<<0) + (r<<8) + (g<<16) + (b<<24);
+		v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
+		*table++ = v;
+	}
+	d_8to24table[255] &= 0xffffff;	// 255 is transparent
+
+	// JACK: 3D distance calcs - k is last closest, l is the distance.
+	// FIXME: Precalculate this and cache to disk.
+	if (palflag)
+		return;
+	palflag = true;
+
+	COM_FOpenFile("glquake/15to8.pal", &f);
+	if (f) {
+		fread(d_15to8table, 1<<15, 1, f);
+		fclose(f);
+	} else {
+		for (i=0; i < (1<<15); i++) {
+			/* Maps
+ 			000000000000000
+ 			000000000011111 = Red  = 0x1F
+ 			000001111100000 = Blue = 0x03E0
+ 			111110000000000 = Grn  = 0x7C00
+ 			*/
+ 			r = ((i & 0x1F) << 3)+4;
+ 			g = ((i & 0x03E0) >> 2)+4;
+ 			b = ((i & 0x7C00) >> 7)+4;
+			pal = (unsigned char *)d_8to24table;
+			for (v=0,k=0,bestdist=10000.0; v<256; v++,pal+=4) {
+ 				r1 = (int)r - (int)pal[0];
+ 				g1 = (int)g - (int)pal[1];
+ 				b1 = (int)b - (int)pal[2];
+				dist = sqrt(((r1*r1)+(g1*g1)+(b1*b1)));
+				if (dist < bestdist) {
+					k=v;
+					bestdist = dist;
+				}
+			}
+			d_15to8table[i]=k;
+		}
+		sprintf(s, "%s/glquake", com_gamedir);
+ 		Sys_mkdir (s);
+		sprintf(s, "%s/glquake/15to8.pal", com_gamedir);
+		if ((f = fopen(s, "wb")) != NULL) {
+			fwrite(d_15to8table, 1<<15, 1, f);
+			fclose(f);
+		}
+	}
+}
+
+/*
+===============
+GL_Init
+===============
+*/
+void GL_Init (void)
+{
+	gl_vendor = (char*) glGetString (GL_VENDOR);
+	Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
+	gl_renderer = (char*) glGetString (GL_RENDERER);
+	Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
+
+	gl_version = (char*) glGetString (GL_VERSION);
+	Con_Printf ("GL_VERSION: %s\n", gl_version);
+	gl_extensions = (char*) glGetString (GL_EXTENSIONS);
+	Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
+
+//	Con_Printf ("%s %s\n", gl_renderer, gl_version);
+
+	glClearColor (1,0,0,0);
+	glCullFace(GL_FRONT);
+	glEnable(GL_TEXTURE_2D);
+
+	glEnable(GL_ALPHA_TEST);
+	glAlphaFunc(GL_GREATER, 0.666);
+
+#ifdef USE_OPENGLES
+#else
+	glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+#endif
+	glShadeModel (GL_FLAT);
+
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+//	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+}
+
+/*
+=================
+GL_BeginRendering
+
+=================
+*/
+void GL_BeginRendering (int *x, int *y, int *width, int *height)
+{
+	extern cvar_t gl_clear;
+
+	*x = *y = 0;
+	*width = scr_width;
+	*height = scr_height;
+
+//    if (!wglMakeCurrent( maindc, baseRC ))
+//		Sys_Error ("wglMakeCurrent failed");
+
+//	glViewport (*x, *y, *width, *height);
+}
+
+
+void GL_EndRendering (void)
+{
+	glFlush();
+	// !!! Swap buffers.
+}
+
+void Init_KBD(void)
+{
+}
+
+qboolean VID_Is8bit(void)
+{
+	return 0;
+}
+
+void VID_Init(unsigned char *palette)
+{
+	int i;
+	GLint attribs[32];
+	char	gldir[MAX_OSPATH];
+	int width = scr_width, height = scr_height;
+
+	S_Init();
+
+	Init_KBD();
+
+	Cvar_RegisterVariable (&gl_ztrick);
+	
+	vid.maxwarpwidth = scr_width;
+	vid.maxwarpheight = height;
+	vid.colormap = host_colormap;
+	vid.fullbright = 0xffff;
+	vid.aspect = (float) scr_width / (float) scr_height;
+	vid.numpages = 2;
+	vid.rowbytes = 2 * scr_width;
+	vid.width = scr_width;
+	vid.height = scr_height;
+	
+	vid.conwidth = scr_width;
+	vid.conheight = scr_height;
+
+// interpret command-line params
+
+// set vid parameters
+
+	GL_Init();
+
+	sprintf (gldir, "%s/glquake", com_gamedir);
+	Sys_mkdir (gldir);
+
+	VID_SetPalette(palette);
+
+	Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
+
+	vid.recalc_refdef = 1;				// force a surface cache flush
+}
+
+// Android Key event codes. These are from the simulator.
+// Not all Android devices can generate all codes.
+
+byte scantokey[] =
+{
+    '$', '$', '$', '$',  '$', '$', '$', '0', //  0.. 7
+    '1', '2', '3', '4',  '5', '6', '7', '8', //  8..15
+    '9', '$', '$', K_UPARROW,  K_DOWNARROW, K_LEFTARROW, K_RIGHTARROW, K_ENTER, // 16..23
+    '$', '$', '$', '$',  '$', 'a', 'b', 'c', // 24..31
+
+    'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', // 32..39
+    'l', 'm', 'n', 'o',  'p', 'q', 'r', 's', // 40..47
+    't', 'u', 'v', 'w',  'x', 'y', 'z', ',', // 48..55
+    '.', K_CTRL, K_SHIFT, K_TAB,  ' ', '$', '$', '$', // 56..63
+	K_ENTER, K_BACKSPACE, '`', '-',  '=', '$', '$', '$', // 64..71
+	'$', '$', '$', '$',  '$', '$', '$', '/', // 72..79
+};
+	
+// return non-zero if the event is handled
+
+int AndroidEvent(int type, int value)
+{
+	if(value >= 0 && value < (int) sizeof(scantokey))
+	{
+		byte key = scantokey[value];
+		Key_Event(key, type);
+		// printf("type: %d, value: %d -> %d '%c'\n", type, value, key, key);
+		return 1;
+	}
+	else
+	{
+		printf("unexpected event type: %d, value: %d\n", type, value);
+	}
+	return 0;
+}
+
+void Sys_SendKeyEvents(void)
+{
+}
+
+void Force_CenterView_f (void)
+{
+	cl.viewangles[PITCH] = 0;
+}
+
+void IN_Init(void)
+{
+}
+
+void IN_Shutdown(void)
+{
+}
+
+/*
+===========
+IN_Commands
+===========
+*/
+void IN_Commands (void)
+{
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void IN_MouseMove (usercmd_t *cmd)
+{
+
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+	IN_MouseMove(cmd);
+}
+
+void VID_UnlockBuffer() {}
+void VID_LockBuffer() {}
+
diff --git a/quake/src/QW/client/gl_vidlinux.c b/quake/src/QW/client/gl_vidlinux.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_vidlinux_svga.c b/quake/src/QW/client/gl_vidlinux_svga.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_vidlinux_x11.c b/quake/src/QW/client/gl_vidlinux_x11.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_vidlinuxglx.c b/quake/src/QW/client/gl_vidlinuxglx.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_vidnt.c b/quake/src/QW/client/gl_vidnt.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/gl_warp.c b/quake/src/QW/client/gl_warp.c
old mode 100644
new mode 100755
index f4344c6..e6bab54
--- a/quake/src/QW/client/gl_warp.c
+++ b/quake/src/QW/client/gl_warp.c
@@ -1,1087 +1,1099 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// gl_warp.c -- sky and water polygons

-

-#include "quakedef.h"

-

-extern	model_t	*loadmodel;

-

-int		skytexturenum;

-

-int		solidskytexture;

-int		alphaskytexture;

-float	speedscale;		// for top sky and bottom sky

-

-msurface_t	*warpface;

-

-extern cvar_t gl_subdivide_size;

-

-void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)

-{

-	int		i, j;

-	float	*v;

-

-	mins[0] = mins[1] = mins[2] = 9999;

-	maxs[0] = maxs[1] = maxs[2] = -9999;

-	v = verts;

-	for (i=0 ; i<numverts ; i++)

-		for (j=0 ; j<3 ; j++, v++)

-		{

-			if (*v < mins[j])

-				mins[j] = *v;

-			if (*v > maxs[j])

-				maxs[j] = *v;

-		}

-}

-

-void SubdividePolygon (int numverts, float *verts)

-{

-	int		i, j, k;

-	vec3_t	mins, maxs;

-	float	m;

-	float	*v;

-	vec3_t	front[64], back[64];

-	int		f, b;

-	float	dist[64];

-	float	frac;

-	glpoly_t	*poly;

-	float	s, t;

-

-	if (numverts > 60)

-		Sys_Error ("numverts = %i", numverts);

-

-	BoundPoly (numverts, verts, mins, maxs);

-

-	for (i=0 ; i<3 ; i++)

-	{

-		m = (mins[i] + maxs[i]) * 0.5;

-		m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);

-		if (maxs[i] - m < 8)

-			continue;

-		if (m - mins[i] < 8)

-			continue;

-

-		// cut it

-		v = verts + i;

-		for (j=0 ; j<numverts ; j++, v+= 3)

-			dist[j] = *v - m;

-

-		// wrap cases

-		dist[j] = dist[0];

-		v-=i;

-		VectorCopy (verts, v);

-

-		f = b = 0;

-		v = verts;

-		for (j=0 ; j<numverts ; j++, v+= 3)

-		{

-			if (dist[j] >= 0)

-			{

-				VectorCopy (v, front[f]);

-				f++;

-			}

-			if (dist[j] <= 0)

-			{

-				VectorCopy (v, back[b]);

-				b++;

-			}

-			if (dist[j] == 0 || dist[j+1] == 0)

-				continue;

-			if ( (dist[j] > 0) != (dist[j+1] > 0) )

-			{

-				// clip point

-				frac = dist[j] / (dist[j] - dist[j+1]);

-				for (k=0 ; k<3 ; k++)

-					front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);

-				f++;

-				b++;

-			}

-		}

-

-		SubdividePolygon (f, front[0]);

-		SubdividePolygon (b, back[0]);

-		return;

-	}

-

-	poly = Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));

-	poly->next = warpface->polys;

-	warpface->polys = poly;

-	poly->numverts = numverts;

-	for (i=0 ; i<numverts ; i++, verts+= 3)

-	{

-		VectorCopy (verts, poly->verts[i]);

-		s = DotProduct (verts, warpface->texinfo->vecs[0]);

-		t = DotProduct (verts, warpface->texinfo->vecs[1]);

-		poly->verts[i][3] = s;

-		poly->verts[i][4] = t;

-	}

-}

-

-/*

-================

-GL_SubdivideSurface

-

-Breaks a polygon up along axial 64 unit

-boundaries so that turbulent and sky warps

-can be done reasonably.

-================

-*/

-void GL_SubdivideSurface (msurface_t *fa)

-{

-	vec3_t		verts[64];

-	int			numverts;

-	int			i;

-	int			lindex;

-	float		*vec;

-

-	warpface = fa;

-

-	//

-	// convert edges back to a normal polygon

-	//

-	numverts = 0;

-	for (i=0 ; i<fa->numedges ; i++)

-	{

-		lindex = loadmodel->surfedges[fa->firstedge + i];

-

-		if (lindex > 0)

-			vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;

-		else

-			vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;

-		VectorCopy (vec, verts[numverts]);

-		numverts++;

-	}

-

-	SubdividePolygon (numverts, verts[0]);

-}

-

-//=========================================================

-

-

-

-// speed up sin calculations - Ed

-float	turbsin[] =

-{

-	#include "gl_warp_sin.h"

-};

-#define TURBSCALE (256.0 / (2 * M_PI))

-

-/*

-=============

-EmitWaterPolys

-

-Does a water warp on the pre-fragmented glpoly_t chain

-=============

-*/

-void EmitWaterPolys (msurface_t *fa)

-{

-	glpoly_t	*p;

-	float		*v;

-	int			i;

-	float		s, t, os, ot;

-

-

-	for (p=fa->polys ; p ; p=p->next)

-	{

-		glBegin (GL_POLYGON);

-		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)

-		{

-			os = v[3];

-			ot = v[4];

-

-			s = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255];

-			s *= (1.0/64);

-

-			t = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255];

-			t *= (1.0/64);

-

-			glTexCoord2f (s, t);

-			glVertex3fv (v);

-		}

-		glEnd ();

-	}

-}

-

-

-

-

-/*

-=============

-EmitSkyPolys

-=============

-*/

-void EmitSkyPolys (msurface_t *fa)

-{

-	glpoly_t	*p;

-	float		*v;

-	int			i;

-	float	s, t;

-	vec3_t	dir;

-	float	length;

-

-	for (p=fa->polys ; p ; p=p->next)

-	{

-		glBegin (GL_POLYGON);

-		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)

-		{

-			VectorSubtract (v, r_origin, dir);

-			dir[2] *= 3;	// flatten the sphere

-

-			length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];

-			length = sqrt (length);

-			length = 6*63/length;

-

-			dir[0] *= length;

-			dir[1] *= length;

-

-			s = (speedscale + dir[0]) * (1.0/128);

-			t = (speedscale + dir[1]) * (1.0/128);

-

-			glTexCoord2f (s, t);

-			glVertex3fv (v);

-		}

-		glEnd ();

-	}

-}

-

-/*

-===============

-EmitBothSkyLayers

-

-Does a sky warp on the pre-fragmented glpoly_t chain

-This will be called for brushmodels, the world

-will have them chained together.

-===============

-*/

-void EmitBothSkyLayers (msurface_t *fa)

-{

-	GL_DisableMultitexture();

-

-	GL_Bind (solidskytexture);

-	speedscale = realtime*8;

-	speedscale -= (int)speedscale & ~127 ;

-

-	EmitSkyPolys (fa);

-

-	glEnable (GL_BLEND);

-	GL_Bind (alphaskytexture);

-	speedscale = realtime*16;

-	speedscale -= (int)speedscale & ~127 ;

-

-	EmitSkyPolys (fa);

-

-	glDisable (GL_BLEND);

-}

-

-#ifndef QUAKE2

-/*

-=================

-R_DrawSkyChain

-=================

-*/

-void R_DrawSkyChain (msurface_t *s)

-{

-	msurface_t	*fa;

-

-	GL_DisableMultitexture();

-

-	// used when gl_texsort is on

-	GL_Bind(solidskytexture);

-	speedscale = realtime*8;

-	speedscale -= (int)speedscale & ~127 ;

-

-	for (fa=s ; fa ; fa=fa->texturechain)

-		EmitSkyPolys (fa);

-

-	glEnable (GL_BLEND);

-	GL_Bind (alphaskytexture);

-	speedscale = realtime*16;

-	speedscale -= (int)speedscale & ~127 ;

-

-	for (fa=s ; fa ; fa=fa->texturechain)

-		EmitSkyPolys (fa);

-

-	glDisable (GL_BLEND);

-}

-

-#endif

-

-/*

-=================================================================

-

-  Quake 2 environment sky

-

-=================================================================

-*/

-

-#ifdef QUAKE2

-

-

-#define	SKY_TEX		2000

-

-/*

-=================================================================

-

-  PCX Loading

-

-=================================================================

-*/

-

-typedef struct

-{

-    char	manufacturer;

-    char	version;

-    char	encoding;

-    char	bits_per_pixel;

-    unsigned short	xmin,ymin,xmax,ymax;

-    unsigned short	hres,vres;

-    unsigned char	palette[48];

-    char	reserved;

-    char	color_planes;

-    unsigned short	bytes_per_line;

-    unsigned short	palette_type;

-    char	filler[58];

-    unsigned 	data;			// unbounded

-} pcx_t;

-

-byte	*pcx_rgb;

-

-/*

-============

-LoadPCX

-============

-*/

-void LoadPCX (FILE *f)

-{

-	pcx_t	*pcx, pcxbuf;

-	byte	palette[768];

-	byte	*pix;

-	int		x, y;

-	int		dataByte, runLength;

-	int		count;

-

-//

-// parse the PCX file

-//

-	fread (&pcxbuf, 1, sizeof(pcxbuf), f);

-

-	pcx = &pcxbuf;

-

-	if (pcx->manufacturer != 0x0a

-		|| pcx->version != 5

-		|| pcx->encoding != 1

-		|| pcx->bits_per_pixel != 8

-		|| pcx->xmax >= 320

-		|| pcx->ymax >= 256)

-	{

-		Con_Printf ("Bad pcx file\n");

-		return;

-	}

-

-	// seek to palette

-	fseek (f, -768, SEEK_END);

-	fread (palette, 1, 768, f);

-

-	fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);

-

-	count = (pcx->xmax+1) * (pcx->ymax+1);

-	pcx_rgb = malloc( count * 4);

-

-	for (y=0 ; y<=pcx->ymax ; y++)

-	{

-		pix = pcx_rgb + 4*y*(pcx->xmax+1);

-		for (x=0 ; x<=pcx->ymax ; )

-		{

-			dataByte = fgetc(f);

-

-			if((dataByte & 0xC0) == 0xC0)

-			{

-				runLength = dataByte & 0x3F;

-				dataByte = fgetc(f);

-			}

-			else

-				runLength = 1;

-

-			while(runLength-- > 0)

-			{

-				pix[0] = palette[dataByte*3];

-				pix[1] = palette[dataByte*3+1];

-				pix[2] = palette[dataByte*3+2];

-				pix[3] = 255;

-				pix += 4;

-				x++;

-			}

-		}

-	}

-}

-

-/*

-=========================================================

-

-TARGA LOADING

-

-=========================================================

-*/

-

-typedef struct _TargaHeader {

-	unsigned char 	id_length, colormap_type, image_type;

-	unsigned short	colormap_index, colormap_length;

-	unsigned char	colormap_size;

-	unsigned short	x_origin, y_origin, width, height;

-	unsigned char	pixel_size, attributes;

-} TargaHeader;

-

-

-TargaHeader		targa_header;

-byte			*targa_rgba;

-

-int fgetLittleShort (FILE *f)

-{

-	byte	b1, b2;

-

-	b1 = fgetc(f);

-	b2 = fgetc(f);

-

-	return (short)(b1 + b2*256);

-}

-

-int fgetLittleLong (FILE *f)

-{

-	byte	b1, b2, b3, b4;

-

-	b1 = fgetc(f);

-	b2 = fgetc(f);

-	b3 = fgetc(f);

-	b4 = fgetc(f);

-

-	return b1 + (b2<<8) + (b3<<16) + (b4<<24);

-}

-

-

-/*

-=============

-LoadTGA

-=============

-*/

-void LoadTGA (FILE *fin)

-{

-	int				columns, rows, numPixels;

-	byte			*pixbuf;

-	int				row, column;

-

-	targa_header.id_length = fgetc(fin);

-	targa_header.colormap_type = fgetc(fin);

-	targa_header.image_type = fgetc(fin);

-	

-	targa_header.colormap_index = fgetLittleShort(fin);

-	targa_header.colormap_length = fgetLittleShort(fin);

-	targa_header.colormap_size = fgetc(fin);

-	targa_header.x_origin = fgetLittleShort(fin);

-	targa_header.y_origin = fgetLittleShort(fin);

-	targa_header.width = fgetLittleShort(fin);

-	targa_header.height = fgetLittleShort(fin);

-	targa_header.pixel_size = fgetc(fin);

-	targa_header.attributes = fgetc(fin);

-

-	if (targa_header.image_type!=2 

-		&& targa_header.image_type!=10) 

-		Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");

-

-	if (targa_header.colormap_type !=0 

-		|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))

-		Sys_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");

-

-	columns = targa_header.width;

-	rows = targa_header.height;

-	numPixels = columns * rows;

-

-	targa_rgba = malloc (numPixels*4);

-	

-	if (targa_header.id_length != 0)

-		fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment

-	

-	if (targa_header.image_type==2) {  // Uncompressed, RGB images

-		for(row=rows-1; row>=0; row--) {

-			pixbuf = targa_rgba + row*columns*4;

-			for(column=0; column<columns; column++) {

-				unsigned char red,green,blue,alphabyte;

-				switch (targa_header.pixel_size) {

-					case 24:

-							

-							blue = getc(fin);

-							green = getc(fin);

-							red = getc(fin);

-							*pixbuf++ = red;

-							*pixbuf++ = green;

-							*pixbuf++ = blue;

-							*pixbuf++ = 255;

-							break;

-					case 32:

-							blue = getc(fin);

-							green = getc(fin);

-							red = getc(fin);

-							alphabyte = getc(fin);

-							*pixbuf++ = red;

-							*pixbuf++ = green;

-							*pixbuf++ = blue;

-							*pixbuf++ = alphabyte;

-							break;

-				}

-			}

-		}

-	}

-	else if (targa_header.image_type==10) {   // Runlength encoded RGB images

-		unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;

-		for(row=rows-1; row>=0; row--) {

-			pixbuf = targa_rgba + row*columns*4;

-			for(column=0; column<columns; ) {

-				packetHeader=getc(fin);

-				packetSize = 1 + (packetHeader & 0x7f);

-				if (packetHeader & 0x80) {        // run-length packet

-					switch (targa_header.pixel_size) {

-						case 24:

-								blue = getc(fin);

-								green = getc(fin);

-								red = getc(fin);

-								alphabyte = 255;

-								break;

-						case 32:

-								blue = getc(fin);

-								green = getc(fin);

-								red = getc(fin);

-								alphabyte = getc(fin);

-								break;

-					}

-	

-					for(j=0;j<packetSize;j++) {

-						*pixbuf++=red;

-						*pixbuf++=green;

-						*pixbuf++=blue;

-						*pixbuf++=alphabyte;

-						column++;

-						if (column==columns) { // run spans across rows

-							column=0;

-							if (row>0)

-								row--;

-							else

-								goto breakOut;

-							pixbuf = targa_rgba + row*columns*4;

-						}

-					}

-				}

-				else {                            // non run-length packet

-					for(j=0;j<packetSize;j++) {

-						switch (targa_header.pixel_size) {

-							case 24:

-									blue = getc(fin);

-									green = getc(fin);

-									red = getc(fin);

-									*pixbuf++ = red;

-									*pixbuf++ = green;

-									*pixbuf++ = blue;

-									*pixbuf++ = 255;

-									break;

-							case 32:

-									blue = getc(fin);

-									green = getc(fin);

-									red = getc(fin);

-									alphabyte = getc(fin);

-									*pixbuf++ = red;

-									*pixbuf++ = green;

-									*pixbuf++ = blue;

-									*pixbuf++ = alphabyte;

-									break;

-						}

-						column++;

-						if (column==columns) { // pixel packet run spans across rows

-							column=0;

-							if (row>0)

-								row--;

-							else

-								goto breakOut;

-							pixbuf = targa_rgba + row*columns*4;

-						}						

-					}

-				}

-			}

-			breakOut:;

-		}

-	}

-	

-	fclose(fin);

-}

-

-/*

-==================

-R_LoadSkys

-==================

-*/

-char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};

-void R_LoadSkys (void)

-{

-	int		i;

-	FILE	*f;

-	char	name[64];

-

-	for (i=0 ; i<6 ; i++)

-	{

-		GL_Bind (SKY_TEX + i);

-		sprintf (name, "gfx/env/bkgtst%s.tga", suf[i]);

-		COM_FOpenFile (name, &f);

-		if (!f)

-		{

-			Con_Printf ("Couldn't load %s\n", name);

-			continue;

-		}

-		LoadTGA (f);

-//		LoadPCX (f);

-

-		glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, targa_rgba);

-//		glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pcx_rgb);

-

-		free (targa_rgba);

-//		free (pcx_rgb);

-

-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

-	}

-}

-

-

-vec3_t	skyclip[6] = {

-	{1,1,0},

-	{1,-1,0},

-	{0,-1,1},

-	{0,1,1},

-	{1,0,1},

-	{-1,0,1} 

-};

-int	c_sky;

-

-// 1 = s, 2 = t, 3 = 2048

-int	st_to_vec[6][3] =

-{

-	{3,-1,2},

-	{-3,1,2},

-

-	{1,3,2},

-	{-1,-3,2},

-

-	{-2,-1,3},		// 0 degrees yaw, look straight up

-	{2,-1,-3}		// look straight down

-

-//	{-1,2,3},

-//	{1,2,-3}

-};

-

-// s = [0]/[2], t = [1]/[2]

-int	vec_to_st[6][3] =

-{

-	{-2,3,1},

-	{2,3,-1},

-

-	{1,3,2},

-	{-1,3,-2},

-

-	{-2,-1,3},

-	{-2,1,-3}

-

-//	{-1,2,3},

-//	{1,2,-3}

-};

-

-float	skymins[2][6], skymaxs[2][6];

-

-void DrawSkyPolygon (int nump, vec3_t vecs)

-{

-	int		i,j;

-	vec3_t	v, av;

-	float	s, t, dv;

-	int		axis;

-	float	*vp;

-

-	c_sky++;

-#if 0

-glBegin (GL_POLYGON);

-for (i=0 ; i<nump ; i++, vecs+=3)

-{

-	VectorAdd(vecs, r_origin, v);

-	glVertex3fv (v);

-}

-glEnd();

-return;

-#endif

-	// decide which face it maps to

-	VectorCopy (vec3_origin, v);

-	for (i=0, vp=vecs ; i<nump ; i++, vp+=3)

-	{

-		VectorAdd (vp, v, v);

-	}

-	av[0] = fabs(v[0]);

-	av[1] = fabs(v[1]);

-	av[2] = fabs(v[2]);

-	if (av[0] > av[1] && av[0] > av[2])

-	{

-		if (v[0] < 0)

-			axis = 1;

-		else

-			axis = 0;

-	}

-	else if (av[1] > av[2] && av[1] > av[0])

-	{

-		if (v[1] < 0)

-			axis = 3;

-		else

-			axis = 2;

-	}

-	else

-	{

-		if (v[2] < 0)

-			axis = 5;

-		else

-			axis = 4;

-	}

-

-	// project new texture coords

-	for (i=0 ; i<nump ; i++, vecs+=3)

-	{

-		j = vec_to_st[axis][2];

-		if (j > 0)

-			dv = vecs[j - 1];

-		else

-			dv = -vecs[-j - 1];

-

-		j = vec_to_st[axis][0];

-		if (j < 0)

-			s = -vecs[-j -1] / dv;

-		else

-			s = vecs[j-1] / dv;

-		j = vec_to_st[axis][1];

-		if (j < 0)

-			t = -vecs[-j -1] / dv;

-		else

-			t = vecs[j-1] / dv;

-

-		if (s < skymins[0][axis])

-			skymins[0][axis] = s;

-		if (t < skymins[1][axis])

-			skymins[1][axis] = t;

-		if (s > skymaxs[0][axis])

-			skymaxs[0][axis] = s;

-		if (t > skymaxs[1][axis])

-			skymaxs[1][axis] = t;

-	}

-}

-

-#define	MAX_CLIP_VERTS	64

-void ClipSkyPolygon (int nump, vec3_t vecs, int stage)

-{

-	float	*norm;

-	float	*v;

-	qboolean	front, back;

-	float	d, e;

-	float	dists[MAX_CLIP_VERTS];

-	int		sides[MAX_CLIP_VERTS];

-	vec3_t	newv[2][MAX_CLIP_VERTS];

-	int		newc[2];

-	int		i, j;

-

-	if (nump > MAX_CLIP_VERTS-2)

-		Sys_Error ("ClipSkyPolygon: MAX_CLIP_VERTS");

-	if (stage == 6)

-	{	// fully clipped, so draw it

-		DrawSkyPolygon (nump, vecs);

-		return;

-	}

-

-	front = back = false;

-	norm = skyclip[stage];

-	for (i=0, v = vecs ; i<nump ; i++, v+=3)

-	{

-		d = DotProduct (v, norm);

-		if (d > ON_EPSILON)

-		{

-			front = true;

-			sides[i] = SIDE_FRONT;

-		}

-		else if (d < ON_EPSILON)

-		{

-			back = true;

-			sides[i] = SIDE_BACK;

-		}

-		else

-			sides[i] = SIDE_ON;

-		dists[i] = d;

-	}

-

-	if (!front || !back)

-	{	// not clipped

-		ClipSkyPolygon (nump, vecs, stage+1);

-		return;

-	}

-

-	// clip it

-	sides[i] = sides[0];

-	dists[i] = dists[0];

-	VectorCopy (vecs, (vecs+(i*3)) );

-	newc[0] = newc[1] = 0;

-

-	for (i=0, v = vecs ; i<nump ; i++, v+=3)

-	{

-		switch (sides[i])

-		{

-		case SIDE_FRONT:

-			VectorCopy (v, newv[0][newc[0]]);

-			newc[0]++;

-			break;

-		case SIDE_BACK:

-			VectorCopy (v, newv[1][newc[1]]);

-			newc[1]++;

-			break;

-		case SIDE_ON:

-			VectorCopy (v, newv[0][newc[0]]);

-			newc[0]++;

-			VectorCopy (v, newv[1][newc[1]]);

-			newc[1]++;

-			break;

-		}

-

-		if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])

-			continue;

-

-		d = dists[i] / (dists[i] - dists[i+1]);

-		for (j=0 ; j<3 ; j++)

-		{

-			e = v[j] + d*(v[j+3] - v[j]);

-			newv[0][newc[0]][j] = e;

-			newv[1][newc[1]][j] = e;

-		}

-		newc[0]++;

-		newc[1]++;

-	}

-

-	// continue

-	ClipSkyPolygon (newc[0], newv[0][0], stage+1);

-	ClipSkyPolygon (newc[1], newv[1][0], stage+1);

-}

-

-/*

-=================

-R_DrawSkyChain

-=================

-*/

-void R_DrawSkyChain (msurface_t *s)

-{

-	msurface_t	*fa;

-

-	int		i;

-	vec3_t	verts[MAX_CLIP_VERTS];

-	glpoly_t	*p;

-

-	c_sky = 0;

-	GL_Bind(solidskytexture);

-

-	// calculate vertex values for sky box

-

-	for (fa=s ; fa ; fa=fa->texturechain)

-	{

-		for (p=fa->polys ; p ; p=p->next)

-		{

-			for (i=0 ; i<p->numverts ; i++)

-			{

-				VectorSubtract (p->verts[i], r_origin, verts[i]);

-			}

-			ClipSkyPolygon (p->numverts, verts[0], 0);

-		}

-	}

-}

-

-

-/*

-==============

-R_ClearSkyBox

-==============

-*/

-void R_ClearSkyBox (void)

-{

-	int		i;

-

-	for (i=0 ; i<6 ; i++)

-	{

-		skymins[0][i] = skymins[1][i] = 9999;

-		skymaxs[0][i] = skymaxs[1][i] = -9999;

-	}

-}

-

-

-void MakeSkyVec (float s, float t, int axis)

-{

-	vec3_t		v, b;

-	int			j, k;

-

-	b[0] = s*2048;

-	b[1] = t*2048;

-	b[2] = 2048;

-

-	for (j=0 ; j<3 ; j++)

-	{

-		k = st_to_vec[axis][j];

-		if (k < 0)

-			v[j] = -b[-k - 1];

-		else

-			v[j] = b[k - 1];

-		v[j] += r_origin[j];

-	}

-

-	// avoid bilerp seam

-	s = (s+1)*0.5;

-	t = (t+1)*0.5;

-

-	if (s < 1.0/512)

-		s = 1.0/512;

-	else if (s > 511.0/512)

-		s = 511.0/512;

-	if (t < 1.0/512)

-		t = 1.0/512;

-	else if (t > 511.0/512)

-		t = 511.0/512;

-

-	t = 1.0 - t;

-	glTexCoord2f (s, t);

-	glVertex3fv (v);

-}

-

-/*

-==============

-R_DrawSkyBox

-==============

-*/

-int	skytexorder[6] = {0,2,1,3,4,5};

-void R_DrawSkyBox (void)

-{

-	int		i, j, k;

-	vec3_t	v;

-	float	s, t;

-

-#if 0

-glEnable (GL_BLEND);

-glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

-glColor4f (1,1,1,0.5);

-glDisable (GL_DEPTH_TEST);

-#endif

-	for (i=0 ; i<6 ; i++)

-	{

-		if (skymins[0][i] >= skymaxs[0][i]

-		|| skymins[1][i] >= skymaxs[1][i])

-			continue;

-

-		GL_Bind (SKY_TEX+skytexorder[i]);

-#if 0

-skymins[0][i] = -1;

-skymins[1][i] = -1;

-skymaxs[0][i] = 1;

-skymaxs[1][i] = 1;

-#endif

-		glBegin (GL_QUADS);

-		MakeSkyVec (skymins[0][i], skymins[1][i], i);

-		MakeSkyVec (skymins[0][i], skymaxs[1][i], i);

-		MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i);

-		MakeSkyVec (skymaxs[0][i], skymins[1][i], i);

-		glEnd ();

-	}

-#if 0

-glDisable (GL_BLEND);

-glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

-glColor4f (1,1,1,0.5);

-glEnable (GL_DEPTH_TEST);

-#endif

-}

-

-

-#endif

-

-//===============================================================

-

-/*

-=============

-R_InitSky

-

-A sky texture is 256*128, with the right side being a masked overlay

-==============

-*/

-void R_InitSky (texture_t *mt)

-{

-	int			i, j, p;

-	byte		*src;

-	unsigned	trans[128*128];

-	unsigned	transpix;

-	int			r, g, b;

-	unsigned	*rgba;

-	extern	int			skytexturenum;

-

-	src = (byte *)mt + mt->offsets[0];

-

-	// make an average value for the back to avoid

-	// a fringe on the top level

-

-	r = g = b = 0;

-	for (i=0 ; i<128 ; i++)

-		for (j=0 ; j<128 ; j++)

-		{

-			p = src[i*256 + j + 128];

-			rgba = &d_8to24table[p];

-			trans[(i*128) + j] = *rgba;

-			r += ((byte *)rgba)[0];

-			g += ((byte *)rgba)[1];

-			b += ((byte *)rgba)[2];

-		}

-

-	((byte *)&transpix)[0] = r/(128*128);

-	((byte *)&transpix)[1] = g/(128*128);

-	((byte *)&transpix)[2] = b/(128*128);

-	((byte *)&transpix)[3] = 0;

-

-

-	if (!solidskytexture)

-		solidskytexture = texture_extension_number++;

-	GL_Bind (solidskytexture );

-	glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

-

-

-	for (i=0 ; i<128 ; i++)

-		for (j=0 ; j<128 ; j++)

-		{

-			p = src[i*256 + j];

-			if (p == 0)

-				trans[(i*128) + j] = transpix;

-			else

-				trans[(i*128) + j] = d_8to24table[p];

-		}

-

-	if (!alphaskytexture)

-		alphaskytexture = texture_extension_number++;

-	GL_Bind(alphaskytexture);

-	glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// gl_warp.c -- sky and water polygons
+
+#include "quakedef.h"
+
+extern	model_t	*loadmodel;
+
+int		skytexturenum;
+
+int		solidskytexture;
+int		alphaskytexture;
+float	speedscale;		// for top sky and bottom sky
+
+msurface_t	*warpface;
+
+extern cvar_t gl_subdivide_size;
+
+void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
+{
+	int		i, j;
+	float	*v;
+
+	mins[0] = mins[1] = mins[2] = 9999;
+	maxs[0] = maxs[1] = maxs[2] = -9999;
+	v = verts;
+	for (i=0 ; i<numverts ; i++)
+		for (j=0 ; j<3 ; j++, v++)
+		{
+			if (*v < mins[j])
+				mins[j] = *v;
+			if (*v > maxs[j])
+				maxs[j] = *v;
+		}
+}
+
+void SubdividePolygon (int numverts, float *verts)
+{
+	int		i, j, k;
+	vec3_t	mins, maxs;
+	float	m;
+	float	*v;
+	vec3_t	front[64], back[64];
+	int		f, b;
+	float	dist[64];
+	float	frac;
+	glpoly_t	*poly;
+	float	s, t;
+
+	if (numverts > 60)
+		Sys_Error ("numverts = %i", numverts);
+
+	BoundPoly (numverts, verts, mins, maxs);
+
+	for (i=0 ; i<3 ; i++)
+	{
+		m = (mins[i] + maxs[i]) * 0.5;
+		m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);
+		if (maxs[i] - m < 8)
+			continue;
+		if (m - mins[i] < 8)
+			continue;
+
+		// cut it
+		v = verts + i;
+		for (j=0 ; j<numverts ; j++, v+= 3)
+			dist[j] = *v - m;
+
+		// wrap cases
+		dist[j] = dist[0];
+		v-=i;
+		VectorCopy (verts, v);
+
+		f = b = 0;
+		v = verts;
+		for (j=0 ; j<numverts ; j++, v+= 3)
+		{
+			if (dist[j] >= 0)
+			{
+				VectorCopy (v, front[f]);
+				f++;
+			}
+			if (dist[j] <= 0)
+			{
+				VectorCopy (v, back[b]);
+				b++;
+			}
+			if (dist[j] == 0 || dist[j+1] == 0)
+				continue;
+			if ( (dist[j] > 0) != (dist[j+1] > 0) )
+			{
+				// clip point
+				frac = dist[j] / (dist[j] - dist[j+1]);
+				for (k=0 ; k<3 ; k++)
+					front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);
+				f++;
+				b++;
+			}
+		}
+
+		SubdividePolygon (f, front[0]);
+		SubdividePolygon (b, back[0]);
+		return;
+	}
+
+	poly = Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));
+	poly->next = warpface->polys;
+	warpface->polys = poly;
+	poly->numverts = numverts;
+	for (i=0 ; i<numverts ; i++, verts+= 3)
+	{
+		VectorCopy (verts, poly->verts[i]);
+		s = DotProduct (verts, warpface->texinfo->vecs[0]);
+		t = DotProduct (verts, warpface->texinfo->vecs[1]);
+		poly->verts[i][3] = s;
+		poly->verts[i][4] = t;
+	}
+}
+
+/*
+================
+GL_SubdivideSurface
+
+Breaks a polygon up along axial 64 unit
+boundaries so that turbulent and sky warps
+can be done reasonably.
+================
+*/
+void GL_SubdivideSurface (msurface_t *fa)
+{
+	vec3_t		verts[64];
+	int			numverts;
+	int			i;
+	int			lindex;
+	float		*vec;
+
+	warpface = fa;
+
+	//
+	// convert edges back to a normal polygon
+	//
+	numverts = 0;
+	for (i=0 ; i<fa->numedges ; i++)
+	{
+		lindex = loadmodel->surfedges[fa->firstedge + i];
+
+		if (lindex > 0)
+			vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
+		else
+			vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
+		VectorCopy (vec, verts[numverts]);
+		numverts++;
+	}
+
+	SubdividePolygon (numverts, verts[0]);
+}
+
+//=========================================================
+
+
+
+// speed up sin calculations - Ed
+float	turbsin[] =
+{
+	#include "gl_warp_sin.h"
+};
+#define TURBSCALE (256.0 / (2 * M_PI))
+
+/*
+=============
+EmitWaterPolys
+
+Does a water warp on the pre-fragmented glpoly_t chain
+=============
+*/
+void EmitWaterPolys (msurface_t *fa)
+{
+	glpoly_t	*p;
+	float		*v;
+	int			i;
+	float		s, t, os, ot;
+
+
+	for (p=fa->polys ; p ; p=p->next)
+	{
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
+		glBegin (GL_POLYGON);
+		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
+		{
+			os = v[3];
+			ot = v[4];
+
+			s = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255];
+			s *= (1.0/64);
+
+			t = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255];
+			t *= (1.0/64);
+
+			glTexCoord2f (s, t);
+			glVertex3fv (v);
+		}
+		glEnd ();
+#endif
+	}
+}
+
+
+
+
+/*
+=============
+EmitSkyPolys
+=============
+*/
+void EmitSkyPolys (msurface_t *fa)
+{
+	glpoly_t	*p;
+	float		*v;
+	int			i;
+	float	s, t;
+	vec3_t	dir;
+	float	length;
+
+	for (p=fa->polys ; p ; p=p->next)
+	{
+#ifdef USE_OPENGLES
+	// !!! Implement this.
+#else
+		glBegin (GL_POLYGON);
+		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
+		{
+			VectorSubtract (v, r_origin, dir);
+			dir[2] *= 3;	// flatten the sphere
+
+			length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
+			length = sqrt (length);
+			length = 6*63/length;
+
+			dir[0] *= length;
+			dir[1] *= length;
+
+			s = (speedscale + dir[0]) * (1.0/128);
+			t = (speedscale + dir[1]) * (1.0/128);
+
+			glTexCoord2f (s, t);
+			glVertex3fv (v);
+		}
+		glEnd ();
+#endif
+	}
+}
+
+/*
+===============
+EmitBothSkyLayers
+
+Does a sky warp on the pre-fragmented glpoly_t chain
+This will be called for brushmodels, the world
+will have them chained together.
+===============
+*/
+void EmitBothSkyLayers (msurface_t *fa)
+{
+	GL_DisableMultitexture();
+
+	GL_Bind (solidskytexture);
+	speedscale = realtime*8;
+	speedscale -= (int)speedscale & ~127 ;
+
+	EmitSkyPolys (fa);
+
+	glEnable (GL_BLEND);
+	GL_Bind (alphaskytexture);
+	speedscale = realtime*16;
+	speedscale -= (int)speedscale & ~127 ;
+
+	EmitSkyPolys (fa);
+
+	glDisable (GL_BLEND);
+}
+
+#ifndef QUAKE2
+/*
+=================
+R_DrawSkyChain
+=================
+*/
+void R_DrawSkyChain (msurface_t *s)
+{
+	msurface_t	*fa;
+
+	GL_DisableMultitexture();
+
+	// used when gl_texsort is on
+	GL_Bind(solidskytexture);
+	speedscale = realtime*8;
+	speedscale -= (int)speedscale & ~127 ;
+
+	for (fa=s ; fa ; fa=fa->texturechain)
+		EmitSkyPolys (fa);
+
+	glEnable (GL_BLEND);
+	GL_Bind (alphaskytexture);
+	speedscale = realtime*16;
+	speedscale -= (int)speedscale & ~127 ;
+
+	for (fa=s ; fa ; fa=fa->texturechain)
+		EmitSkyPolys (fa);
+
+	glDisable (GL_BLEND);
+}
+
+#endif
+
+/*
+=================================================================
+
+  Quake 2 environment sky
+
+=================================================================
+*/
+
+#ifdef QUAKE2
+
+
+#define	SKY_TEX		2000
+
+/*
+=================================================================
+
+  PCX Loading
+
+=================================================================
+*/
+
+typedef struct
+{
+    char	manufacturer;
+    char	version;
+    char	encoding;
+    char	bits_per_pixel;
+    unsigned short	xmin,ymin,xmax,ymax;
+    unsigned short	hres,vres;
+    unsigned char	palette[48];
+    char	reserved;
+    char	color_planes;
+    unsigned short	bytes_per_line;
+    unsigned short	palette_type;
+    char	filler[58];
+    unsigned 	data;			// unbounded
+} pcx_t;
+
+byte	*pcx_rgb;
+
+/*
+============
+LoadPCX
+============
+*/
+void LoadPCX (FILE *f)
+{
+	pcx_t	*pcx, pcxbuf;
+	byte	palette[768];
+	byte	*pix;
+	int		x, y;
+	int		dataByte, runLength;
+	int		count;
+
+//
+// parse the PCX file
+//
+	fread (&pcxbuf, 1, sizeof(pcxbuf), f);
+
+	pcx = &pcxbuf;
+
+	if (pcx->manufacturer != 0x0a
+		|| pcx->version != 5
+		|| pcx->encoding != 1
+		|| pcx->bits_per_pixel != 8
+		|| pcx->xmax >= 320
+		|| pcx->ymax >= 256)
+	{
+		Con_Printf ("Bad pcx file\n");
+		return;
+	}
+
+	// seek to palette
+	fseek (f, -768, SEEK_END);
+	fread (palette, 1, 768, f);
+
+	fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
+
+	count = (pcx->xmax+1) * (pcx->ymax+1);
+	pcx_rgb = malloc( count * 4);
+
+	for (y=0 ; y<=pcx->ymax ; y++)
+	{
+		pix = pcx_rgb + 4*y*(pcx->xmax+1);
+		for (x=0 ; x<=pcx->ymax ; )
+		{
+			dataByte = fgetc(f);
+
+			if((dataByte & 0xC0) == 0xC0)
+			{
+				runLength = dataByte & 0x3F;
+				dataByte = fgetc(f);
+			}
+			else
+				runLength = 1;
+
+			while(runLength-- > 0)
+			{
+				pix[0] = palette[dataByte*3];
+				pix[1] = palette[dataByte*3+1];
+				pix[2] = palette[dataByte*3+2];
+				pix[3] = 255;
+				pix += 4;
+				x++;
+			}
+		}
+	}
+}
+
+/*
+=========================================================
+
+TARGA LOADING
+
+=========================================================
+*/
+
+typedef struct _TargaHeader {
+	unsigned char 	id_length, colormap_type, image_type;
+	unsigned short	colormap_index, colormap_length;
+	unsigned char	colormap_size;
+	unsigned short	x_origin, y_origin, width, height;
+	unsigned char	pixel_size, attributes;
+} TargaHeader;
+
+
+TargaHeader		targa_header;
+byte			*targa_rgba;
+
+int fgetLittleShort (FILE *f)
+{
+	byte	b1, b2;
+
+	b1 = fgetc(f);
+	b2 = fgetc(f);
+
+	return (short)(b1 + b2*256);
+}
+
+int fgetLittleLong (FILE *f)
+{
+	byte	b1, b2, b3, b4;
+
+	b1 = fgetc(f);
+	b2 = fgetc(f);
+	b3 = fgetc(f);
+	b4 = fgetc(f);
+
+	return b1 + (b2<<8) + (b3<<16) + (b4<<24);
+}
+
+
+/*
+=============
+LoadTGA
+=============
+*/
+void LoadTGA (FILE *fin)
+{
+	int				columns, rows, numPixels;
+	byte			*pixbuf;
+	int				row, column;
+
+	targa_header.id_length = fgetc(fin);
+	targa_header.colormap_type = fgetc(fin);
+	targa_header.image_type = fgetc(fin);
+	
+	targa_header.colormap_index = fgetLittleShort(fin);
+	targa_header.colormap_length = fgetLittleShort(fin);
+	targa_header.colormap_size = fgetc(fin);
+	targa_header.x_origin = fgetLittleShort(fin);
+	targa_header.y_origin = fgetLittleShort(fin);
+	targa_header.width = fgetLittleShort(fin);
+	targa_header.height = fgetLittleShort(fin);
+	targa_header.pixel_size = fgetc(fin);
+	targa_header.attributes = fgetc(fin);
+
+	if (targa_header.image_type!=2 
+		&& targa_header.image_type!=10) 
+		Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
+
+	if (targa_header.colormap_type !=0 
+		|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
+		Sys_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+
+	columns = targa_header.width;
+	rows = targa_header.height;
+	numPixels = columns * rows;
+
+	targa_rgba = malloc (numPixels*4);
+	
+	if (targa_header.id_length != 0)
+		fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment
+	
+	if (targa_header.image_type==2) {  // Uncompressed, RGB images
+		for(row=rows-1; row>=0; row--) {
+			pixbuf = targa_rgba + row*columns*4;
+			for(column=0; column<columns; column++) {
+				unsigned char red,green,blue,alphabyte;
+				switch (targa_header.pixel_size) {
+					case 24:
+							
+							blue = getc(fin);
+							green = getc(fin);
+							red = getc(fin);
+							*pixbuf++ = red;
+							*pixbuf++ = green;
+							*pixbuf++ = blue;
+							*pixbuf++ = 255;
+							break;
+					case 32:
+							blue = getc(fin);
+							green = getc(fin);
+							red = getc(fin);
+							alphabyte = getc(fin);
+							*pixbuf++ = red;
+							*pixbuf++ = green;
+							*pixbuf++ = blue;
+							*pixbuf++ = alphabyte;
+							break;
+				}
+			}
+		}
+	}
+	else if (targa_header.image_type==10) {   // Runlength encoded RGB images
+		unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
+		for(row=rows-1; row>=0; row--) {
+			pixbuf = targa_rgba + row*columns*4;
+			for(column=0; column<columns; ) {
+				packetHeader=getc(fin);
+				packetSize = 1 + (packetHeader & 0x7f);
+				if (packetHeader & 0x80) {        // run-length packet
+					switch (targa_header.pixel_size) {
+						case 24:
+								blue = getc(fin);
+								green = getc(fin);
+								red = getc(fin);
+								alphabyte = 255;
+								break;
+						case 32:
+								blue = getc(fin);
+								green = getc(fin);
+								red = getc(fin);
+								alphabyte = getc(fin);
+								break;
+					}
+	
+					for(j=0;j<packetSize;j++) {
+						*pixbuf++=red;
+						*pixbuf++=green;
+						*pixbuf++=blue;
+						*pixbuf++=alphabyte;
+						column++;
+						if (column==columns) { // run spans across rows
+							column=0;
+							if (row>0)
+								row--;
+							else
+								goto breakOut;
+							pixbuf = targa_rgba + row*columns*4;
+						}
+					}
+				}
+				else {                            // non run-length packet
+					for(j=0;j<packetSize;j++) {
+						switch (targa_header.pixel_size) {
+							case 24:
+									blue = getc(fin);
+									green = getc(fin);
+									red = getc(fin);
+									*pixbuf++ = red;
+									*pixbuf++ = green;
+									*pixbuf++ = blue;
+									*pixbuf++ = 255;
+									break;
+							case 32:
+									blue = getc(fin);
+									green = getc(fin);
+									red = getc(fin);
+									alphabyte = getc(fin);
+									*pixbuf++ = red;
+									*pixbuf++ = green;
+									*pixbuf++ = blue;
+									*pixbuf++ = alphabyte;
+									break;
+						}
+						column++;
+						if (column==columns) { // pixel packet run spans across rows
+							column=0;
+							if (row>0)
+								row--;
+							else
+								goto breakOut;
+							pixbuf = targa_rgba + row*columns*4;
+						}						
+					}
+				}
+			}
+			breakOut:;
+		}
+	}
+	
+	fclose(fin);
+}
+
+/*
+==================
+R_LoadSkys
+==================
+*/
+char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+void R_LoadSkys (void)
+{
+	int		i;
+	FILE	*f;
+	char	name[64];
+
+	for (i=0 ; i<6 ; i++)
+	{
+		GL_Bind (SKY_TEX + i);
+		sprintf (name, "gfx/env/bkgtst%s.tga", suf[i]);
+		COM_FOpenFile (name, &f);
+		if (!f)
+		{
+			Con_Printf ("Couldn't load %s\n", name);
+			continue;
+		}
+		LoadTGA (f);
+//		LoadPCX (f);
+
+		glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, targa_rgba);
+//		glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pcx_rgb);
+
+		free (targa_rgba);
+//		free (pcx_rgb);
+
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	}
+}
+
+
+vec3_t	skyclip[6] = {
+	{1,1,0},
+	{1,-1,0},
+	{0,-1,1},
+	{0,1,1},
+	{1,0,1},
+	{-1,0,1} 
+};
+int	c_sky;
+
+// 1 = s, 2 = t, 3 = 2048
+int	st_to_vec[6][3] =
+{
+	{3,-1,2},
+	{-3,1,2},
+
+	{1,3,2},
+	{-1,-3,2},
+
+	{-2,-1,3},		// 0 degrees yaw, look straight up
+	{2,-1,-3}		// look straight down
+
+//	{-1,2,3},
+//	{1,2,-3}
+};
+
+// s = [0]/[2], t = [1]/[2]
+int	vec_to_st[6][3] =
+{
+	{-2,3,1},
+	{2,3,-1},
+
+	{1,3,2},
+	{-1,3,-2},
+
+	{-2,-1,3},
+	{-2,1,-3}
+
+//	{-1,2,3},
+//	{1,2,-3}
+};
+
+float	skymins[2][6], skymaxs[2][6];
+
+void DrawSkyPolygon (int nump, vec3_t vecs)
+{
+	int		i,j;
+	vec3_t	v, av;
+	float	s, t, dv;
+	int		axis;
+	float	*vp;
+
+	c_sky++;
+#if 0
+glBegin (GL_POLYGON);
+for (i=0 ; i<nump ; i++, vecs+=3)
+{
+	VectorAdd(vecs, r_origin, v);
+	glVertex3fv (v);
+}
+glEnd();
+return;
+#endif
+	// decide which face it maps to
+	VectorCopy (vec3_origin, v);
+	for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
+	{
+		VectorAdd (vp, v, v);
+	}
+	av[0] = fabs(v[0]);
+	av[1] = fabs(v[1]);
+	av[2] = fabs(v[2]);
+	if (av[0] > av[1] && av[0] > av[2])
+	{
+		if (v[0] < 0)
+			axis = 1;
+		else
+			axis = 0;
+	}
+	else if (av[1] > av[2] && av[1] > av[0])
+	{
+		if (v[1] < 0)
+			axis = 3;
+		else
+			axis = 2;
+	}
+	else
+	{
+		if (v[2] < 0)
+			axis = 5;
+		else
+			axis = 4;
+	}
+
+	// project new texture coords
+	for (i=0 ; i<nump ; i++, vecs+=3)
+	{
+		j = vec_to_st[axis][2];
+		if (j > 0)
+			dv = vecs[j - 1];
+		else
+			dv = -vecs[-j - 1];
+
+		j = vec_to_st[axis][0];
+		if (j < 0)
+			s = -vecs[-j -1] / dv;
+		else
+			s = vecs[j-1] / dv;
+		j = vec_to_st[axis][1];
+		if (j < 0)
+			t = -vecs[-j -1] / dv;
+		else
+			t = vecs[j-1] / dv;
+
+		if (s < skymins[0][axis])
+			skymins[0][axis] = s;
+		if (t < skymins[1][axis])
+			skymins[1][axis] = t;
+		if (s > skymaxs[0][axis])
+			skymaxs[0][axis] = s;
+		if (t > skymaxs[1][axis])
+			skymaxs[1][axis] = t;
+	}
+}
+
+#define	MAX_CLIP_VERTS	64
+void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
+{
+	float	*norm;
+	float	*v;
+	qboolean	front, back;
+	float	d, e;
+	float	dists[MAX_CLIP_VERTS];
+	int		sides[MAX_CLIP_VERTS];
+	vec3_t	newv[2][MAX_CLIP_VERTS];
+	int		newc[2];
+	int		i, j;
+
+	if (nump > MAX_CLIP_VERTS-2)
+		Sys_Error ("ClipSkyPolygon: MAX_CLIP_VERTS");
+	if (stage == 6)
+	{	// fully clipped, so draw it
+		DrawSkyPolygon (nump, vecs);
+		return;
+	}
+
+	front = back = false;
+	norm = skyclip[stage];
+	for (i=0, v = vecs ; i<nump ; i++, v+=3)
+	{
+		d = DotProduct (v, norm);
+		if (d > ON_EPSILON)
+		{
+			front = true;
+			sides[i] = SIDE_FRONT;
+		}
+		else if (d < ON_EPSILON)
+		{
+			back = true;
+			sides[i] = SIDE_BACK;
+		}
+		else
+			sides[i] = SIDE_ON;
+		dists[i] = d;
+	}
+
+	if (!front || !back)
+	{	// not clipped
+		ClipSkyPolygon (nump, vecs, stage+1);
+		return;
+	}
+
+	// clip it
+	sides[i] = sides[0];
+	dists[i] = dists[0];
+	VectorCopy (vecs, (vecs+(i*3)) );
+	newc[0] = newc[1] = 0;
+
+	for (i=0, v = vecs ; i<nump ; i++, v+=3)
+	{
+		switch (sides[i])
+		{
+		case SIDE_FRONT:
+			VectorCopy (v, newv[0][newc[0]]);
+			newc[0]++;
+			break;
+		case SIDE_BACK:
+			VectorCopy (v, newv[1][newc[1]]);
+			newc[1]++;
+			break;
+		case SIDE_ON:
+			VectorCopy (v, newv[0][newc[0]]);
+			newc[0]++;
+			VectorCopy (v, newv[1][newc[1]]);
+			newc[1]++;
+			break;
+		}
+
+		if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+			continue;
+
+		d = dists[i] / (dists[i] - dists[i+1]);
+		for (j=0 ; j<3 ; j++)
+		{
+			e = v[j] + d*(v[j+3] - v[j]);
+			newv[0][newc[0]][j] = e;
+			newv[1][newc[1]][j] = e;
+		}
+		newc[0]++;
+		newc[1]++;
+	}
+
+	// continue
+	ClipSkyPolygon (newc[0], newv[0][0], stage+1);
+	ClipSkyPolygon (newc[1], newv[1][0], stage+1);
+}
+
+/*
+=================
+R_DrawSkyChain
+=================
+*/
+void R_DrawSkyChain (msurface_t *s)
+{
+	msurface_t	*fa;
+
+	int		i;
+	vec3_t	verts[MAX_CLIP_VERTS];
+	glpoly_t	*p;
+
+	c_sky = 0;
+	GL_Bind(solidskytexture);
+
+	// calculate vertex values for sky box
+
+	for (fa=s ; fa ; fa=fa->texturechain)
+	{
+		for (p=fa->polys ; p ; p=p->next)
+		{
+			for (i=0 ; i<p->numverts ; i++)
+			{
+				VectorSubtract (p->verts[i], r_origin, verts[i]);
+			}
+			ClipSkyPolygon (p->numverts, verts[0], 0);
+		}
+	}
+}
+
+
+/*
+==============
+R_ClearSkyBox
+==============
+*/
+void R_ClearSkyBox (void)
+{
+	int		i;
+
+	for (i=0 ; i<6 ; i++)
+	{
+		skymins[0][i] = skymins[1][i] = 9999;
+		skymaxs[0][i] = skymaxs[1][i] = -9999;
+	}
+}
+
+
+void MakeSkyVec (float s, float t, int axis)
+{
+	vec3_t		v, b;
+	int			j, k;
+
+	b[0] = s*2048;
+	b[1] = t*2048;
+	b[2] = 2048;
+
+	for (j=0 ; j<3 ; j++)
+	{
+		k = st_to_vec[axis][j];
+		if (k < 0)
+			v[j] = -b[-k - 1];
+		else
+			v[j] = b[k - 1];
+		v[j] += r_origin[j];
+	}
+
+	// avoid bilerp seam
+	s = (s+1)*0.5;
+	t = (t+1)*0.5;
+
+	if (s < 1.0/512)
+		s = 1.0/512;
+	else if (s > 511.0/512)
+		s = 511.0/512;
+	if (t < 1.0/512)
+		t = 1.0/512;
+	else if (t > 511.0/512)
+		t = 511.0/512;
+
+	t = 1.0 - t;
+	glTexCoord2f (s, t);
+	glVertex3fv (v);
+}
+
+/*
+==============
+R_DrawSkyBox
+==============
+*/
+int	skytexorder[6] = {0,2,1,3,4,5};
+void R_DrawSkyBox (void)
+{
+	int		i, j, k;
+	vec3_t	v;
+	float	s, t;
+
+#if 0
+glEnable (GL_BLEND);
+glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+glColor4f (1,1,1,0.5);
+glDisable (GL_DEPTH_TEST);
+#endif
+	for (i=0 ; i<6 ; i++)
+	{
+		if (skymins[0][i] >= skymaxs[0][i]
+		|| skymins[1][i] >= skymaxs[1][i])
+			continue;
+
+		GL_Bind (SKY_TEX+skytexorder[i]);
+#if 0
+skymins[0][i] = -1;
+skymins[1][i] = -1;
+skymaxs[0][i] = 1;
+skymaxs[1][i] = 1;
+#endif
+#ifdef USE_OPENGLES
+		// !!! Implement this
+#else
+		glBegin (GL_QUADS);
+		MakeSkyVec (skymins[0][i], skymins[1][i], i);
+		MakeSkyVec (skymins[0][i], skymaxs[1][i], i);
+		MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i);
+		MakeSkyVec (skymaxs[0][i], skymins[1][i], i);
+		glEnd ();
+#endif
+	}
+#if 0
+glDisable (GL_BLEND);
+glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+glColor4f (1,1,1,0.5);
+glEnable (GL_DEPTH_TEST);
+#endif
+}
+
+
+#endif
+
+//===============================================================
+
+/*
+=============
+R_InitSky
+
+A sky texture is 256*128, with the right side being a masked overlay
+==============
+*/
+void R_InitSky (texture_t *mt)
+{
+	int			i, j, p;
+	byte		*src;
+	unsigned	trans[128*128];
+	unsigned	transpix;
+	int			r, g, b;
+	unsigned	*rgba;
+	extern	int			skytexturenum;
+
+	src = (byte *)mt + mt->offsets[0];
+
+	// make an average value for the back to avoid
+	// a fringe on the top level
+
+	r = g = b = 0;
+	for (i=0 ; i<128 ; i++)
+		for (j=0 ; j<128 ; j++)
+		{
+			p = src[i*256 + j + 128];
+			rgba = &d_8to24table[p];
+			trans[(i*128) + j] = *rgba;
+			r += ((byte *)rgba)[0];
+			g += ((byte *)rgba)[1];
+			b += ((byte *)rgba)[2];
+		}
+
+	((byte *)&transpix)[0] = r/(128*128);
+	((byte *)&transpix)[1] = g/(128*128);
+	((byte *)&transpix)[2] = b/(128*128);
+	((byte *)&transpix)[3] = 0;
+
+
+	if (!solidskytexture)
+		solidskytexture = texture_extension_number++;
+	GL_Bind (solidskytexture );
+	glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+
+	for (i=0 ; i<128 ; i++)
+		for (j=0 ; j<128 ; j++)
+		{
+			p = src[i*256 + j];
+			if (p == 0)
+				trans[(i*128) + j] = transpix;
+			else
+				trans[(i*128) + j] = d_8to24table[p];
+		}
+
+	if (!alphaskytexture)
+		alphaskytexture = texture_extension_number++;
+	GL_Bind(alphaskytexture);
+	glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+}
+
diff --git a/quake/src/QW/client/gl_warp_sin.h b/quake/src/QW/client/gl_warp_sin.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/glquake.h b/quake/src/QW/client/glquake.h
old mode 100644
new mode 100755
index 5c4e1f2..cbf5f3a
--- a/quake/src/QW/client/glquake.h
+++ b/quake/src/QW/client/glquake.h
@@ -1,302 +1,327 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// disable data conversion warnings

-

-#pragma warning(disable : 4244)     // MIPS

-#pragma warning(disable : 4136)     // X86

-#pragma warning(disable : 4051)     // ALPHA

-  

-#ifdef _WIN32

-#include <windows.h>

-#endif

-

-#include <GL/gl.h>

-#include <GL/glu.h>

-

-void GL_BeginRendering (int *x, int *y, int *width, int *height);

-void GL_EndRendering (void);

-

-

-// Function prototypes for the Texture Object Extension routines

-typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,

-                    const GLboolean *);

-typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint);

-typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *);

-typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *);

-typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint);

-typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *,

-                    const GLclampf *);

-typedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *);

-

-extern	BINDTEXFUNCPTR bindTexFunc;

-extern	DELTEXFUNCPTR delTexFunc;

-extern	TEXSUBIMAGEPTR TexSubImage2DFunc;

-

-extern	int texture_extension_number;

-extern	int		texture_mode;

-

-extern	float	gldepthmin, gldepthmax;

-

-void GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap, qboolean alpha);

-void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);

-void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);

-int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha);

-int GL_FindTexture (char *identifier);

-

-typedef struct

-{

-	float	x, y, z;

-	float	s, t;

-	float	r, g, b;

-} glvert_t;

-

-extern glvert_t glv;

-

-extern	int glx, gly, glwidth, glheight;

-

-#ifdef _WIN32

-extern	PROC glArrayElementEXT;

-extern	PROC glColorPointerEXT;

-extern	PROC glTexturePointerEXT;

-extern	PROC glVertexPointerEXT;

-#endif

-

-// r_local.h -- private refresh defs

-

-#define ALIAS_BASE_SIZE_RATIO		(1.0 / 11.0)

-					// normalizing factor so player model works out to about

-					//  1 pixel per triangle

-#define	MAX_LBM_HEIGHT		480

-

-#define TILE_SIZE		128		// size of textures generated by R_GenTiledSurf

-

-#define SKYSHIFT		7

-#define	SKYSIZE			(1 << SKYSHIFT)

-#define SKYMASK			(SKYSIZE - 1)

-

-#define BACKFACE_EPSILON	0.01

-

-

-void R_TimeRefresh_f (void);

-void R_ReadPointFile_f (void);

-texture_t *R_TextureAnimation (texture_t *base);

-

-typedef struct surfcache_s

-{

-	struct surfcache_s	*next;

-	struct surfcache_s 	**owner;		// NULL is an empty chunk of memory

-	int					lightadj[MAXLIGHTMAPS]; // checked for strobe flush

-	int					dlight;

-	int					size;		// including header

-	unsigned			width;

-	unsigned			height;		// DEBUG only needed for debug

-	float				mipscale;

-	struct texture_s	*texture;	// checked for animating textures

-	byte				data[4];	// width*height elements

-} surfcache_t;

-

-

-typedef struct

-{

-	pixel_t		*surfdat;	// destination for generated surface

-	int			rowbytes;	// destination logical width in bytes

-	msurface_t	*surf;		// description for surface to generate

-	fixed8_t	lightadj[MAXLIGHTMAPS];

-							// adjust for lightmap levels for dynamic lighting

-	texture_t	*texture;	// corrected for animating textures

-	int			surfmip;	// mipmapped ratio of surface texels / world pixels

-	int			surfwidth;	// in mipmapped texels

-	int			surfheight;	// in mipmapped texels

-} drawsurf_t;

-

-

-typedef enum {

-	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2

-} ptype_t;

-

-// !!! if this is changed, it must be changed in d_ifacea.h too !!!

-typedef struct particle_s

-{

-// driver-usable fields

-	vec3_t		org;

-	float		color;

-// drivers never touch the following fields

-	struct particle_s	*next;

-	vec3_t		vel;

-	float		ramp;

-	float		die;

-	ptype_t		type;

-} particle_t;

-

-

-//====================================================

-

-

-extern	entity_t	r_worldentity;

-extern	qboolean	r_cache_thrash;		// compatability

-extern	vec3_t		modelorg, r_entorigin;

-extern	entity_t	*currententity;

-extern	int			r_visframecount;	// ??? what difs?

-extern	int			r_framecount;

-extern	mplane_t	frustum[4];

-extern	int		c_brush_polys, c_alias_polys;

-

-

-//

-// view origin

-//

-extern	vec3_t	vup;

-extern	vec3_t	vpn;

-extern	vec3_t	vright;

-extern	vec3_t	r_origin;

-

-//

-// screen size info

-//

-extern	refdef_t	r_refdef;

-extern	mleaf_t		*r_viewleaf, *r_oldviewleaf;

-extern	texture_t	*r_notexture_mip;

-extern	int		d_lightstylevalue[256];	// 8.8 fraction of base light value

-

-extern	qboolean	envmap;

-extern	int	currenttexture;

-extern	int	cnttextures[2];

-extern	int	particletexture;

-extern	int	netgraphtexture;	// netgraph texture

-extern	int	playertextures;

-

-extern	int	skytexturenum;		// index in cl.loadmodel, not gl texture object

-

-extern	cvar_t	r_norefresh;

-extern	cvar_t	r_drawentities;

-extern	cvar_t	r_drawworld;

-extern	cvar_t	r_drawviewmodel;

-extern	cvar_t	r_speeds;

-extern	cvar_t	r_waterwarp;

-extern	cvar_t	r_fullbright;

-extern	cvar_t	r_lightmap;

-extern	cvar_t	r_shadows;

-extern	cvar_t	r_mirroralpha;

-extern	cvar_t	r_wateralpha;

-extern	cvar_t	r_dynamic;

-extern	cvar_t	r_novis;

-extern	cvar_t	r_netgraph;

-

-extern	cvar_t	gl_clear;

-extern	cvar_t	gl_cull;

-extern	cvar_t	gl_poly;

-extern	cvar_t	gl_texsort;

-extern	cvar_t	gl_smoothmodels;

-extern	cvar_t	gl_affinemodels;

-extern	cvar_t	gl_polyblend;

-extern	cvar_t	gl_keeptjunctions;

-extern	cvar_t	gl_reporttjunctions;

-extern	cvar_t	gl_flashblend;

-extern	cvar_t	gl_nocolors;

-extern	cvar_t	gl_finish;

-

-extern	int		gl_lightmap_format;

-extern	int		gl_solid_format;

-extern	int		gl_alpha_format;

-

-extern	cvar_t	gl_max_size;

-extern	cvar_t	gl_playermip;

-

-extern	int			mirrortexturenum;	// quake texturenum, not gltexturenum

-extern	qboolean	mirror;

-extern	mplane_t	*mirror_plane;

-

-extern	float	r_world_matrix[16];

-

-extern	const char *gl_vendor;

-extern	const char *gl_renderer;

-extern	const char *gl_version;

-extern	const char *gl_extensions;

-

-void R_TranslatePlayerSkin (int playernum);

-void GL_Bind (int texnum);

-

-// Multitexture

-#define    TEXTURE0_SGIS				0x835E

-#define    TEXTURE1_SGIS				0x835F

-

-#ifdef _WIN32

-typedef void (APIENTRY *lpMTexFUNC) (GLenum, GLfloat, GLfloat);

-typedef void (APIENTRY *lpSelTexFUNC) (GLenum);

-extern lpMTexFUNC qglMTexCoord2fSGIS;

-extern lpSelTexFUNC qglSelectTextureSGIS;

-#endif

-

-extern qboolean gl_mtexable;

-

-void GL_DisableMultitexture(void);

-void GL_EnableMultitexture(void);

-

-//

-// gl_warp.c

-//

-void GL_SubdivideSurface (msurface_t *fa);

-void EmitBothSkyLayers (msurface_t *fa);

-void EmitWaterPolys (msurface_t *fa);

-void EmitSkyPolys (msurface_t *fa);

-void R_DrawSkyChain (msurface_t *s);

-

-//

-// gl_draw.c

-//

-int GL_LoadPicTexture (qpic_t *pic);

-void GL_Set2D (void);

-

-//

-// gl_rmain.c

-//

-qboolean R_CullBox (vec3_t mins, vec3_t maxs);

-void R_RotateForEntity (entity_t *e);

-

-//

-// gl_rlight.c

-//

-void R_MarkLights (dlight_t *light, int bit, mnode_t *node);

-void R_AnimateLight (void);

-void R_RenderDlights (void);

-int R_LightPoint (vec3_t p);

-

-//

-// gl_refrag.c

-//

-void R_StoreEfrags (efrag_t **ppefrag);

-

-//

-// gl_mesh.c

-//

-void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr);

-

-//

-// gl_rsurf.c

-//

-void R_DrawBrushModel (entity_t *e);

-void R_DrawWorld (void);

-void GL_BuildLightmaps (void);

-

-//

-// gl_ngraph.c

-//

-void R_NetGraph (void);

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// disable data conversion warnings
+
+#ifdef _WIN32
+#pragma warning(disable : 4244)     // MIPS
+#pragma warning(disable : 4136)     // X86
+#pragma warning(disable : 4051)     // ALPHA
+#endif
+  
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef USE_OPENGLES
+
+#include <GLES/gl.h>
+
+#else
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#endif
+
+void GL_BeginRendering (int *x, int *y, int *width, int *height);
+void GL_EndRendering (void);
+
+#ifdef USE_OPENGLES
+
+#else // full OpenGL
+
+// Function prototypes for the Texture Object Extension routines
+typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,
+                    const GLboolean *);
+typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint);
+typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *);
+typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *);
+typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint);
+typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *,
+                    const GLclampf *);
+typedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *);
+
+extern	BINDTEXFUNCPTR bindTexFunc;
+extern	DELTEXFUNCPTR delTexFunc;
+extern	TEXSUBIMAGEPTR TexSubImage2DFunc;
+
+#endif // USE_OPENGLES
+
+extern	int texture_extension_number;
+extern	int		texture_mode;
+
+extern	float	gldepthmin, gldepthmax;
+
+void GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap, qboolean alpha);
+void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
+void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
+int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha);
+int GL_FindTexture (char *identifier);
+
+void glTexImage2DHelper( GLenum target,
+	 GLint level,
+	 GLint internalformat,
+	 GLsizei width,
+	 GLsizei height,
+	 GLint border,
+	 GLenum format,
+	 GLenum type,
+	 const GLvoid *pixels );
+
+typedef struct
+{
+	float	x, y, z;
+	float	s, t;
+	float	r, g, b;
+} glvert_t;
+
+extern glvert_t glv;
+
+extern	int glx, gly, glwidth, glheight;
+
+#ifdef _WIN32
+extern	PROC glArrayElementEXT;
+extern	PROC glColorPointerEXT;
+extern	PROC glTexturePointerEXT;
+extern	PROC glVertexPointerEXT;
+#endif
+
+// r_local.h -- private refresh defs
+
+#define ALIAS_BASE_SIZE_RATIO		(1.0 / 11.0)
+					// normalizing factor so player model works out to about
+					//  1 pixel per triangle
+#define	MAX_LBM_HEIGHT		480
+
+#define TILE_SIZE		128		// size of textures generated by R_GenTiledSurf
+
+#define SKYSHIFT		7
+#define	SKYSIZE			(1 << SKYSHIFT)
+#define SKYMASK			(SKYSIZE - 1)
+
+#define BACKFACE_EPSILON	0.01
+
+
+void R_TimeRefresh_f (void);
+void R_ReadPointFile_f (void);
+texture_t *R_TextureAnimation (texture_t *base);
+
+typedef struct surfcache_s
+{
+	struct surfcache_s	*next;
+	struct surfcache_s 	**owner;		// NULL is an empty chunk of memory
+	int					lightadj[MAXLIGHTMAPS]; // checked for strobe flush
+	int					dlight;
+	int					size;		// including header
+	unsigned			width;
+	unsigned			height;		// DEBUG only needed for debug
+	float				mipscale;
+	struct texture_s	*texture;	// checked for animating textures
+	byte				data[4];	// width*height elements
+} surfcache_t;
+
+
+typedef struct
+{
+	pixel_t		*surfdat;	// destination for generated surface
+	int			rowbytes;	// destination logical width in bytes
+	msurface_t	*surf;		// description for surface to generate
+	fixed8_t	lightadj[MAXLIGHTMAPS];
+							// adjust for lightmap levels for dynamic lighting
+	texture_t	*texture;	// corrected for animating textures
+	int			surfmip;	// mipmapped ratio of surface texels / world pixels
+	int			surfwidth;	// in mipmapped texels
+	int			surfheight;	// in mipmapped texels
+} drawsurf_t;
+
+
+typedef enum {
+	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2
+} ptype_t;
+
+// !!! if this is changed, it must be changed in d_ifacea.h too !!!
+typedef struct particle_s
+{
+// driver-usable fields
+	vec3_t		org;
+	float		color;
+// drivers never touch the following fields
+	struct particle_s	*next;
+	vec3_t		vel;
+	float		ramp;
+	float		die;
+	ptype_t		type;
+} particle_t;
+
+
+//====================================================
+
+
+extern	entity_t	r_worldentity;
+extern	qboolean	r_cache_thrash;		// compatability
+extern	vec3_t		modelorg, r_entorigin;
+extern	entity_t	*currententity;
+extern	int			r_visframecount;	// ??? what difs?
+extern	int			r_framecount;
+extern	mplane_t	frustum[4];
+extern	int		c_brush_polys, c_alias_polys;
+
+
+//
+// view origin
+//
+extern	vec3_t	vup;
+extern	vec3_t	vpn;
+extern	vec3_t	vright;
+extern	vec3_t	r_origin;
+
+//
+// screen size info
+//
+extern	refdef_t	r_refdef;
+extern	mleaf_t		*r_viewleaf, *r_oldviewleaf;
+extern	texture_t	*r_notexture_mip;
+extern	int		d_lightstylevalue[256];	// 8.8 fraction of base light value
+
+extern	qboolean	envmap;
+extern	int	currenttexture;
+extern	int	cnttextures[2];
+extern	int	particletexture;
+extern	int	netgraphtexture;	// netgraph texture
+extern	int	playertextures;
+
+extern	int	skytexturenum;		// index in cl.loadmodel, not gl texture object
+
+extern	cvar_t	r_norefresh;
+extern	cvar_t	r_drawentities;
+extern	cvar_t	r_drawworld;
+extern	cvar_t	r_drawviewmodel;
+extern	cvar_t	r_speeds;
+extern	cvar_t	r_waterwarp;
+extern	cvar_t	r_fullbright;
+extern	cvar_t	r_lightmap;
+extern	cvar_t	r_shadows;
+extern	cvar_t	r_mirroralpha;
+extern	cvar_t	r_wateralpha;
+extern	cvar_t	r_dynamic;
+extern	cvar_t	r_novis;
+extern	cvar_t	r_netgraph;
+
+extern	cvar_t	gl_clear;
+extern	cvar_t	gl_cull;
+extern	cvar_t	gl_poly;
+extern	cvar_t	gl_texsort;
+extern	cvar_t	gl_smoothmodels;
+extern	cvar_t	gl_affinemodels;
+extern	cvar_t	gl_polyblend;
+extern	cvar_t	gl_keeptjunctions;
+extern	cvar_t	gl_reporttjunctions;
+extern	cvar_t	gl_flashblend;
+extern	cvar_t	gl_nocolors;
+extern	cvar_t	gl_finish;
+
+extern	int		gl_lightmap_format;
+extern	int		gl_solid_format;
+extern	int		gl_alpha_format;
+
+extern	cvar_t	gl_max_size;
+extern	cvar_t	gl_playermip;
+
+extern	int			mirrortexturenum;	// quake texturenum, not gltexturenum
+extern	qboolean	mirror;
+extern	mplane_t	*mirror_plane;
+
+extern	float	r_world_matrix[16];
+
+extern	const char *gl_vendor;
+extern	const char *gl_renderer;
+extern	const char *gl_version;
+extern	const char *gl_extensions;
+
+void R_TranslatePlayerSkin (int playernum);
+void GL_Bind (int texnum);
+
+// Multitexture
+#define    TEXTURE0_SGIS				0x835E
+#define    TEXTURE1_SGIS				0x835F
+
+#ifdef _WIN32
+typedef void (APIENTRY *lpMTexFUNC) (GLenum, GLfloat, GLfloat);
+typedef void (APIENTRY *lpSelTexFUNC) (GLenum);
+extern lpMTexFUNC qglMTexCoord2fSGIS;
+extern lpSelTexFUNC qglSelectTextureSGIS;
+#endif
+
+extern qboolean gl_mtexable;
+
+void GL_DisableMultitexture(void);
+void GL_EnableMultitexture(void);
+
+//
+// gl_warp.c
+//
+void GL_SubdivideSurface (msurface_t *fa);
+void EmitBothSkyLayers (msurface_t *fa);
+void EmitWaterPolys (msurface_t *fa);
+void EmitSkyPolys (msurface_t *fa);
+void R_DrawSkyChain (msurface_t *s);
+
+//
+// gl_draw.c
+//
+int GL_LoadPicTexture (qpic_t *pic);
+void GL_Set2D (void);
+
+//
+// gl_rmain.c
+//
+qboolean R_CullBox (vec3_t mins, vec3_t maxs);
+void R_RotateForEntity (entity_t *e);
+
+//
+// gl_rlight.c
+//
+void R_MarkLights (dlight_t *light, int bit, mnode_t *node);
+void R_AnimateLight (void);
+void R_RenderDlights (void);
+int R_LightPoint (vec3_t p);
+
+//
+// gl_refrag.c
+//
+void R_StoreEfrags (efrag_t **ppefrag);
+
+//
+// gl_mesh.c
+//
+void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr);
+
+//
+// gl_rsurf.c
+//
+void R_DrawBrushModel (entity_t *e);
+void R_DrawWorld (void);
+void GL_BuildLightmaps (void);
+
+//
+// gl_ngraph.c
+//
+void R_NetGraph (void);
+
diff --git a/quake/src/QW/client/glquake2.h b/quake/src/QW/client/glquake2.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/in_null.c b/quake/src/QW/client/in_null.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/in_win.c b/quake/src/QW/client/in_win.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/input.h b/quake/src/QW/client/input.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/keys.c b/quake/src/QW/client/keys.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/keys.h b/quake/src/QW/client/keys.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/main.cpp b/quake/src/QW/client/main.cpp
new file mode 100644
index 0000000..7ca5a81
--- /dev/null
+++ b/quake/src/QW/client/main.cpp
@@ -0,0 +1,130 @@
+/* //device/apps/Quake/quake/src/QW/client/main.c
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <nativehelper/jni.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <private/opengles/gl_context.h>
+#include <GLES/gl.h>
+
+// Delegate to "C" routines to do the rest of the processing.
+// (We do this because it's difficult to mix the C++ headers
+// for JNI and gl_context with the C headers for quake.)
+
+extern "C"
+{
+void AndroidInit(int width, int height);
+int AndroidEvent(int type, int value);
+void AndroidStep();
+int AndroidQuiting();
+}
+
+void
+qinit(JNIEnv *env, jobject thiz, /* jobjectArray config, */
+       jint width, jint height) {
+	AndroidInit(width, height);
+}
+
+jboolean
+qevent(JNIEnv *env, jobject thiz, jint type, jint value) {
+	return AndroidEvent(type, value) ? JNI_TRUE : JNI_FALSE;
+}
+
+void
+qstep(JNIEnv *env, jobject thiz) {
+	AndroidStep();
+}
+
+jboolean
+qquitting(JNIEnv *env, jobject thiz) {
+  return AndroidQuiting() ? JNI_TRUE : JNI_FALSE;
+}
+
+static const char *classPathName = "com/android/quake/QuakeApplication";
+
+static JNINativeMethod methods[] = {
+  {"init", "(II)V", (void*)qinit },
+  {"event", "(II)Z", (void*)qevent },
+  {"step", "()V", (void*)qstep },
+  {"quitting", "()Z", (void*)qquitting },
+};
+
+/*
+ * Register several native methods for one class.
+ */
+static int registerNativeMethods(JNIEnv* env, const char* className,
+    JNINativeMethod* gMethods, int numMethods)
+{
+    jclass clazz;
+
+    clazz = env->FindClass(className);
+    if (clazz == NULL) {
+        fprintf(stderr,
+            "Native registration unable to find class '%s'\n", className);
+        return JNI_FALSE;
+    }
+    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
+        fprintf(stderr, "RegisterNatives failed for '%s'\n", className);
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+/*
+ * Register native methods for all classes we know about.
+ */
+static int registerNatives(JNIEnv* env)
+{
+  if (!registerNativeMethods(env, classPathName,
+			     methods, sizeof(methods) / sizeof(methods[0]))) {
+    return JNI_FALSE;
+  }
+
+  return JNI_TRUE;
+}
+
+/*
+ * Set some test stuff up.
+ *
+ * Returns the JNI version on success, -1 on failure.
+ */
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        fprintf(stderr, "ERROR: GetEnv failed\n");
+        goto bail;
+    }
+    assert(env != NULL);
+
+    printf("In mgmain JNI_OnLoad\n");
+
+    if (!registerNatives(env)) {
+        fprintf(stderr, "ERROR: miniglobe native registration failed\n");
+        goto bail;
+    }
+
+    /* success -- return valid version number */
+    result = JNI_VERSION_1_4;
+
+bail:
+    return result;
+}
diff --git a/quake/src/QW/client/makefile.svgalib b/quake/src/QW/client/makefile.svgalib
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/math.asm b/quake/src/QW/client/math.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/math.s b/quake/src/QW/client/math.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/mathlib.c b/quake/src/QW/client/mathlib.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/mathlib.h b/quake/src/QW/client/mathlib.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/md4.c b/quake/src/QW/client/md4.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/menu.c b/quake/src/QW/client/menu.c
old mode 100644
new mode 100755
index e9a7126..0a332d0
--- a/quake/src/QW/client/menu.c
+++ b/quake/src/QW/client/menu.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 #include "quakedef.h"
 #include "winquake.h"
 
@@ -738,7 +738,7 @@
 		M_Print (18, 32, "Enter to change, backspace to clear");
 		
 // search for known bindings
-	for (i=0 ; i<NUMCOMMANDS ; i++)
+	for (i=0 ; i< (int) NUMCOMMANDS ; i++)
 	{
 		y = 48 + 8*i;
 
@@ -812,7 +812,7 @@
 	case K_RIGHTARROW:
 		S_LocalSound ("misc/menu1.wav");
 		keys_cursor++;
-		if (keys_cursor >= NUMCOMMANDS)
+		if (keys_cursor >= (int) NUMCOMMANDS)
 			keys_cursor = 0;
 		break;
 
@@ -1017,7 +1017,7 @@
 
 }
 
-void M_SinglePlayer_Key (key) {
+void M_SinglePlayer_Key (int key) {
 	if (key == K_ESCAPE || key==K_ENTER)
 		m_state = m_main;
 }
@@ -1045,7 +1045,7 @@
 	M_PrintWhite (72, 16*8, "        started!        ");
 }
 
-void M_MultiPlayer_Key (key) {
+void M_MultiPlayer_Key (int key) {
 	if (key == K_ESCAPE || key==K_ENTER)
 		m_state = m_main;
 }
diff --git a/quake/src/QW/client/menu.h b/quake/src/QW/client/menu.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/model.c b/quake/src/QW/client/model.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/model.h b/quake/src/QW/client/model.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/modelgen.h b/quake/src/QW/client/modelgen.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/net.h b/quake/src/QW/client/net.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/net_chan.c b/quake/src/QW/client/net_chan.c
old mode 100644
new mode 100755
index ea17a0b..c491297
--- a/quake/src/QW/client/net_chan.c
+++ b/quake/src/QW/client/net_chan.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 #include "quakedef.h"
 
@@ -76,9 +76,9 @@
 */
 
 int		net_drop;
-cvar_t	showpackets = {"showpackets", "0"};
-cvar_t	showdrop = {"showdrop", "0"};
-cvar_t	qport = {"qport", "0"};
+cvar_t	showpackets = CVAR2("showpackets", "0");
+cvar_t	showdrop = CVAR2("showdrop", "0");
+cvar_t	qport = CVAR2("qport", "0");
 
 /*
 ===============
diff --git a/quake/src/QW/client/net_udp.c b/quake/src/QW/client/net_udp.c
old mode 100644
new mode 100755
index 4c76b9c..4507e96
--- a/quake/src/QW/client/net_udp.c
+++ b/quake/src/QW/client/net_udp.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // net_main.c
 
 #include "quakedef.h"
@@ -53,7 +53,7 @@
 #define	MAX_UDP_PACKET	8192
 byte		net_message_buffer[MAX_UDP_PACKET];
 
-int gethostname (char *, int);
+// int gethostname (char *, int);
 int close (int);
 
 //=============================================================================
@@ -192,7 +192,7 @@
 {
 	int 	ret;
 	struct sockaddr_in	from;
-	int		fromlen;
+	socklen_t		fromlen;
 
 	fromlen = sizeof(from);
 	ret = recvfrom (net_socket, net_message_buffer, sizeof(net_message_buffer), 0, (struct sockaddr *)&from, &fromlen);
@@ -265,7 +265,7 @@
 {
 	char	buff[MAXHOSTNAMELEN];
 	struct sockaddr_in	address;
-	int		namelen;
+	socklen_t namelen;
 
 	gethostname(buff, MAXHOSTNAMELEN);
 	buff[MAXHOSTNAMELEN-1] = 0;
diff --git a/quake/src/QW/client/net_wins.c b/quake/src/QW/client/net_wins.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/nonintel.c b/quake/src/QW/client/nonintel.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/notes.txt b/quake/src/QW/client/notes.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/pmove.c b/quake/src/QW/client/pmove.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/pmove.h b/quake/src/QW/client/pmove.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/pmovetst.c b/quake/src/QW/client/pmovetst.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/protocol.h b/quake/src/QW/client/protocol.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/qe3.ico b/quake/src/QW/client/qe3.ico
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/client/quakeasm.h b/quake/src/QW/client/quakeasm.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/quakedef.h b/quake/src/QW/client/quakedef.h
old mode 100644
new mode 100755
index 8355850..e1f057b
--- a/quake/src/QW/client/quakedef.h
+++ b/quake/src/QW/client/quakedef.h
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // quakedef.h -- primary header for client
 
 #define	QUAKE_GAME			// as opposed to utilities
@@ -27,7 +27,11 @@
 #pragma warning( disable : 4244 4127 4201 4214 4514 4305 4115 4018)
 #endif
 
+#define GLQUAKE
+#define USE_OPENGLES
+#define id386 0
 
+#include <ctype.h>
 #include <math.h>
 #include <string.h>
 #include <stdarg.h>
@@ -35,6 +39,7 @@
 #include <stdlib.h>
 #include <setjmp.h>
 #include <time.h>
+#include <unistd.h>
 
 #include "bothdefs.h"
 
@@ -140,3 +145,27 @@
 extern qboolean		msg_suppress_1;		// suppresses resolution and cache size console output
 										//  an fullscreen DIB focus gain/loss
 
+
+// Linux versions of msdos CRT functions
+#define stricmp strcasecmp
+
+// Helper functions for OpenGL ES
+void DrawQuad_NoTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+void DrawQuad(GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat u, GLfloat v, GLfloat uw, GLfloat vh);
+
+void shadowLoadIdentity( GLfloat* m);
+void shadowRotatef( GLfloat* m, GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+void shadowTranslatef( GLfloat* m, GLfloat x, GLfloat y, GLfloat z);
+
+#ifdef USE_OPENGLES
+// Reimplementation of OpenGL functions that are missing in OpenGL ES
+
+#define GL_INTENSITY				0x8049
+
+void glColor3f(GLfloat r, GLfloat g, GLfloat b);
+void glColor4fv(GLfloat* pColor);
+void glColor4ubv(unsigned char* pColor);
+
+
+#endif
+
diff --git a/quake/src/QW/client/quakeworld.bmp b/quake/src/QW/client/quakeworld.bmp
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/client/qwcl.dsp b/quake/src/QW/client/qwcl.dsp
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/qwcl.dsw b/quake/src/QW/client/qwcl.dsw
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/qwcl.mak b/quake/src/QW/client/qwcl.mak
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/qwcl.mdp b/quake/src/QW/client/qwcl.mdp
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/client/qwcl.plg b/quake/src/QW/client/qwcl.plg
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/qwcl2.ico b/quake/src/QW/client/qwcl2.ico
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/client/r_aclip.c b/quake/src/QW/client/r_aclip.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_aclipa.asm b/quake/src/QW/client/r_aclipa.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_aclipa.s b/quake/src/QW/client/r_aclipa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_alias.c b/quake/src/QW/client/r_alias.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_aliasa.asm b/quake/src/QW/client/r_aliasa.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_aliasa.s b/quake/src/QW/client/r_aliasa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_bsp.c b/quake/src/QW/client/r_bsp.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_draw.c b/quake/src/QW/client/r_draw.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_drawa.asm b/quake/src/QW/client/r_drawa.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_drawa.s b/quake/src/QW/client/r_drawa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_edge.c b/quake/src/QW/client/r_edge.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_edgea.asm b/quake/src/QW/client/r_edgea.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_edgea.s b/quake/src/QW/client/r_edgea.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_efrag.c b/quake/src/QW/client/r_efrag.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_light.c b/quake/src/QW/client/r_light.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_local.h b/quake/src/QW/client/r_local.h
old mode 100644
new mode 100755
index acff07b..04fe372
--- a/quake/src/QW/client/r_local.h
+++ b/quake/src/QW/client/r_local.h
@@ -1,25 +1,25 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // r_local.h -- private refresh defs
-

-#ifndef GLQUAKE

+
+#ifndef GLQUAKE
 
 #include "r_shared.h"
 
@@ -171,8 +171,8 @@
 extern void R_Surf8End (void);
 extern void R_Surf16Start (void);
 extern void R_Surf16End (void);
-extern void R_EdgeCodeStart (void);

-extern void R_EdgeCodeEnd (void);

+extern void R_EdgeCodeStart (void);
+extern void R_EdgeCodeEnd (void);
 
 extern void R_RotateBmodel (void);
 
@@ -314,4 +314,4 @@
 void R_SplitEntityOnNode2 (mnode_t *node);
 void R_MarkLights (dlight_t *light, int bit, mnode_t *node);
 
-#endif //GLQUAKE
\ No newline at end of file
+#endif //GLQUAKE
diff --git a/quake/src/QW/client/r_main.c b/quake/src/QW/client/r_main.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_misc.c b/quake/src/QW/client/r_misc.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_part.c b/quake/src/QW/client/r_part.c
old mode 100644
new mode 100755
index 096ade2..c7962d0
--- a/quake/src/QW/client/r_part.c
+++ b/quake/src/QW/client/r_part.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 #include "quakedef.h"
 #include "r_local.h"
@@ -230,14 +230,14 @@
 {
 	int			i, j;
 	particle_t	*p;
-	int			scale;

-

-	if (count > 130)

-		scale = 3;

-	else if (count > 20)

-		scale = 2;

-	else

-		scale = 1;

+	int			scale;
+
+	if (count > 130)
+		scale = 3;
+	else if (count > 20)
+		scale = 2;
+	else
+		scale = 1;
 
 	for (i=0 ; i<count ; i++)
 	{
@@ -453,31 +453,41 @@
 	float			time1;
 	float			dvel;
 	float			frametime;
-#ifdef GLQUAKE

-	unsigned char	*at;

+#ifdef GLQUAKE
+	unsigned char	*at;
 	unsigned char	theAlpha;
-	vec3_t			up, right;

-	float			scale;

-	qboolean		alphaTestEnabled;

-    

-	GL_Bind(particletexture);

-	alphaTestEnabled = glIsEnabled(GL_ALPHA_TEST);

-	

-	if (alphaTestEnabled)

-		glDisable(GL_ALPHA_TEST);

-	glEnable (GL_BLEND);

-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

-	glBegin (GL_TRIANGLES);

-

-	VectorScale (vup, 1.5, up);

-	VectorScale (vright, 1.5, right);

-#else

+	vec3_t			up, right;
+	float			scale;
+	qboolean		alphaTestEnabled;
+    
+	GL_Bind(particletexture);
+#ifdef USE_OPENGLES
+	// !!! Implement this
+	alphaTestEnabled = false;
+#else
+	alphaTestEnabled = glIsEnabled(GL_ALPHA_TEST);
+#endif
+	
+	if (alphaTestEnabled)
+		glDisable(GL_ALPHA_TEST);
+	glEnable (GL_BLEND);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	
+#ifdef USE_OPENGLES
+	// !!! Implement this
+#else
+	glBegin (GL_TRIANGLES);
+#endif
+
+	VectorScale (vup, 1.5, up);
+	VectorScale (vright, 1.5, right);
+#else
 	D_StartParticles ();
 
 	VectorScale (vright, xscaleshrink, r_pright);
 	VectorScale (vup, yscaleshrink, r_pup);
 	VectorCopy (vpn, r_ppn);
-#endif

+#endif
 
 	frametime = host_frametime;
 	time3 = frametime * 15;
@@ -514,35 +524,40 @@
 			break;
 		}
 
-#ifdef GLQUAKE

-		// hack a scale up to keep particles from disapearing

-		scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]

-			+ (p->org[2] - r_origin[2])*vpn[2];

-		if (scale < 20)

-			scale = 1;

-		else

-			scale = 1 + scale * 0.004;

-		at = (byte *)&d_8to24table[(int)p->color];

-		if (p->type==pt_fire)

-			theAlpha = 255*(6-p->ramp)/6;

-//			theAlpha = 192;

-//		else if (p->type==pt_explode || p->type==pt_explode2)

-//			theAlpha = 255*(8-p->ramp)/8;

-		else

-			theAlpha = 255;

-		glColor4ub (*at, *(at+1), *(at+2), theAlpha);

-//		glColor3ubv (at);

-//		glColor3ubv ((byte *)&d_8to24table[(int)p->color]);

-		glTexCoord2f (0,0);

-		glVertex3fv (p->org);

-		glTexCoord2f (1,0);

-		glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);

-		glTexCoord2f (0,1);

-		glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);

-

-#else

+#ifdef GLQUAKE
+		// hack a scale up to keep particles from disapearing
+		scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
+			+ (p->org[2] - r_origin[2])*vpn[2];
+		if (scale < 20)
+			scale = 1;
+		else
+			scale = 1 + scale * 0.004;
+		at = (byte *)&d_8to24table[(int)p->color];
+		if (p->type==pt_fire)
+			theAlpha = 255*(6-p->ramp)/6;
+//			theAlpha = 192;
+//		else if (p->type==pt_explode || p->type==pt_explode2)
+//			theAlpha = 255*(8-p->ramp)/8;
+		else
+			theAlpha = 255;
+
+#ifdef USE_OPENGLES
+	// !!! Implement this
+#else
+		glColor4ub (*at, *(at+1), *(at+2), theAlpha);
+//		glColor3ubv (at);
+//		glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
+		glTexCoord2f (0,0);
+		glVertex3fv (p->org);
+		glTexCoord2f (1,0);
+		glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
+		glTexCoord2f (0,1);
+		glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
+#endif
+
+#else
 		D_DrawParticle (p);
-#endif

+#endif
 
 		p->org[0] += p->vel[0]*frametime;
 		p->org[1] += p->vel[1]*frametime;
@@ -602,14 +617,18 @@
 		}
 	}
 
-#ifdef GLQUAKE

-	glEnd ();

-	glDisable (GL_BLEND);

-	if (alphaTestEnabled)

-		glEnable(GL_ALPHA_TEST);

-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

-#else

-	D_EndParticles ();

+#ifdef GLQUAKE
+#ifdef USE_OPENGLES
+	// !!! Implement this
+#else
+	glEnd ();
+#endif
+	glDisable (GL_BLEND);
+	if (alphaTestEnabled)
+		glEnable(GL_ALPHA_TEST);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+#else
+	D_EndParticles ();
 #endif
 }
 
diff --git a/quake/src/QW/client/r_shared.h b/quake/src/QW/client/r_shared.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_sky.c b/quake/src/QW/client/r_sky.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_sprite.c b/quake/src/QW/client/r_sprite.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_surf.c b/quake/src/QW/client/r_surf.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_vars.c b/quake/src/QW/client/r_vars.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_varsa.asm b/quake/src/QW/client/r_varsa.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/r_varsa.s b/quake/src/QW/client/r_varsa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/render.h b/quake/src/QW/client/render.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/resource.h b/quake/src/QW/client/resource.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sbar.c b/quake/src/QW/client/sbar.c
old mode 100644
new mode 100755
index c36fdf7..14b42f4
--- a/quake/src/QW/client/sbar.c
+++ b/quake/src/QW/client/sbar.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // sbar.c -- status bar code
 
 #include "quakedef.h"
@@ -934,7 +934,7 @@
 // draw the text
 	l = scoreboardlines;
 
-	for (i=0 ; i < scoreboardteams && y <= vid.height-10 ; i++)
+	for (i=0 ; i < scoreboardteams && y <= (int) (vid.height-10) ; i++)
 	{
 		k = teamsort[i];
 		tm = teams + k;
@@ -1055,7 +1055,7 @@
 		y += 8;
 	}
 
-	for (i=0 ; i<l && y <= vid.height-10 ; i++)
+	for (i=0 ; i<l && y <= (int) (vid.height-10) ; i++)
 	{
 		k = fragsort[i];
 		s = &cl.players[k];
@@ -1142,7 +1142,7 @@
 		y += skip;
 	}
 
-	if (y >= vid.height-10) // we ran over the screen size, squish
+	if (y >= (int) (vid.height-10)) // we ran over the screen size, squish
 		largegame = true;
 }
 
@@ -1207,7 +1207,7 @@
 
 	x = 324;
 
-	for (/* */ ; i < scoreboardlines && y < vid.height - 8 + 1; i++)
+	for (/* */ ; i < scoreboardlines && y < (int) (vid.height - 8 + 1); i++)
 	{
 		k = fragsort[i];
 		s = &cl.players[k];
@@ -1261,13 +1261,13 @@
 
 	// draw seperator
 	x += 208;
-	for (y = vid.height - sb_lines; y < vid.height - 6; y += 2)
+	for (y = vid.height - sb_lines; y < (int) (vid.height - 6); y += 2)
 		Draw_Character(x, y, 14);
 
 	x += 16;
 
 	y = vid.height - sb_lines;
-	for (i=0 ; i < scoreboardteams && y <= vid.height; i++)
+	for (i=0 ; i < scoreboardteams && y <= (int) vid.height; i++)
 	{
 		k = teamsort[i];
 		tm = teams + k;
diff --git a/quake/src/QW/client/sbar.h b/quake/src/QW/client/sbar.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/screen.c b/quake/src/QW/client/screen.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/screen.h b/quake/src/QW/client/screen.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/skin.c b/quake/src/QW/client/skin.c
old mode 100644
new mode 100755
index 5330129..f04dc92
--- a/quake/src/QW/client/skin.c
+++ b/quake/src/QW/client/skin.c
@@ -1,27 +1,27 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 #include "quakedef.h"
 
-cvar_t		baseskin = {"baseskin", "base"};
-cvar_t		noskins = {"noskins", "0"};
+cvar_t		baseskin = CVAR2("baseskin", "base");
+cvar_t		noskins = CVAR2("noskins", "0");
 
 char		allskins[128];
 #define	MAX_CACHED_SKINS		128
@@ -79,8 +79,8 @@
 	sc->skin = skin;
 	numskins++;
 
-	memset (skin, 0, sizeof(*skin));

-	strncpy(skin->name, name, sizeof(skin->name) - 1);

+	memset (skin, 0, sizeof(*skin));
+	strncpy(skin->name, name, sizeof(skin->name) - 1);
 }
 
 
@@ -160,36 +160,36 @@
 	{
 		for (x=0 ; x<=pcx->xmax ; )
 		{
-			if (raw - (byte*)pcx > com_filesize) 

-			{

-				Cache_Free (&skin->cache);

-				skin->failedload = true;

-				Con_Printf ("Skin %s was malformed.  You should delete it.\n", name);

-				return NULL;

-			}

+			if (raw - (byte*)pcx > com_filesize) 
+			{
+				Cache_Free (&skin->cache);
+				skin->failedload = true;
+				Con_Printf ("Skin %s was malformed.  You should delete it.\n", name);
+				return NULL;
+			}
 			dataByte = *raw++;
 
 			if((dataByte & 0xC0) == 0xC0)
 			{
 				runLength = dataByte & 0x3F;
-				if (raw - (byte*)pcx > com_filesize) 

-				{

-					Cache_Free (&skin->cache);

-					skin->failedload = true;

-					Con_Printf ("Skin %s was malformed.  You should delete it.\n", name);

-					return NULL;

-				}

+				if (raw - (byte*)pcx > com_filesize) 
+				{
+					Cache_Free (&skin->cache);
+					skin->failedload = true;
+					Con_Printf ("Skin %s was malformed.  You should delete it.\n", name);
+					return NULL;
+				}
 				dataByte = *raw++;
 			}
 			else
 				runLength = 1;
-

-			// skin sanity check

-			if (runLength + x > pcx->xmax + 2) {

-				Cache_Free (&skin->cache);

-				skin->failedload = true;

-				Con_Printf ("Skin %s was malformed.  You should delete it.\n", name);

-				return NULL;

+
+			// skin sanity check
+			if (runLength + x > pcx->xmax + 2) {
+				Cache_Free (&skin->cache);
+				skin->failedload = true;
+				Con_Printf ("Skin %s was malformed.  You should delete it.\n", name);
+				return NULL;
 			}
 			while(runLength-- > 0)
 				pix[x++] = dataByte;
@@ -247,9 +247,9 @@
 		sc = &cl.players[i];
 		if (!sc->name[0])
 			continue;
-		Skin_Cache (sc->skin);

-#ifdef GLQUAKE

-		sc->skin = NULL;

+		Skin_Cache (sc->skin);
+#ifdef GLQUAKE
+		sc->skin = NULL;
 #endif
 	}
 
@@ -257,7 +257,7 @@
 	{	// get next signon phase
 		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
 		MSG_WriteString (&cls.netchan.message,
-			va("begin %i", cl.servercount));

+			va("begin %i", cl.servercount));
 		Cache_Report ();		// print remaining memory
 	}
 }
diff --git a/quake/src/QW/client/snd_android.c b/quake/src/QW/client/snd_android.c
new file mode 100644
index 0000000..1bd9848
--- /dev/null
+++ b/quake/src/QW/client/snd_android.c
@@ -0,0 +1,57 @@
+/*
+ *  snd_android.c
+ *  Android-specific sound interface
+ *
+ */
+
+#include "quakedef.h"
+
+/*
+==================
+SNDDMA_Init
+
+Try to find a sound device to mix for.
+Returns false if nothing is found.
+==================
+*/
+
+qboolean SNDDMA_Init(void)
+{
+	return 0;
+}
+
+/*
+==============
+SNDDMA_GetDMAPos
+
+return the current sample position (in mono samples read)
+inside the recirculating dma buffer, so the mixing code will know
+how many sample are required to fill it up.
+===============
+*/
+int SNDDMA_GetDMAPos(void)
+{
+	return 0;
+}
+
+/*
+==============
+SNDDMA_Submit
+
+Send sound to device if buffer isn't really the dma buffer
+===============
+*/
+void SNDDMA_Submit(void)
+{
+}
+
+/*
+==============
+SNDDMA_Shutdown
+
+Reset the sound device for exiting
+===============
+*/
+void SNDDMA_Shutdown(void)
+{
+}
diff --git a/quake/src/QW/client/snd_dma.c b/quake/src/QW/client/snd_dma.c
old mode 100644
new mode 100755
index e3ee7e8..307af82
--- a/quake/src/QW/client/snd_dma.c
+++ b/quake/src/QW/client/snd_dma.c
@@ -1,1017 +1,1017 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// snd_dma.c -- main control for any streaming sound output device

-

-#include "quakedef.h"

-

-#ifdef _WIN32

-#include "winquake.h"

-#endif

-

-void S_Play(void);

-void S_PlayVol(void);

-void S_SoundList(void);

-void S_Update_();

-void S_StopAllSounds(qboolean clear);

-void S_StopAllSoundsC(void);

-

-// QuakeWorld hack...

-#define	viewentity	playernum+1

-

-// =======================================================================

-// Internal sound data & structures

-// =======================================================================

-

-channel_t   channels[MAX_CHANNELS];

-int			total_channels;

-

-int				snd_blocked = 0;

-static qboolean	snd_ambient = 1;

-qboolean		snd_initialized = false;

-

-// pointer should go away

-volatile dma_t  *shm = 0;

-volatile dma_t sn;

-

-vec3_t		listener_origin;

-vec3_t		listener_forward;

-vec3_t		listener_right;

-vec3_t		listener_up;

-vec_t		sound_nominal_clip_dist=1000.0;

-

-int			soundtime;		// sample PAIRS

-int   		paintedtime; 	// sample PAIRS

-

-

-#define	MAX_SFX		512

-sfx_t		*known_sfx;		// hunk allocated [MAX_SFX]

-int			num_sfx;

-

-sfx_t		*ambient_sfx[NUM_AMBIENTS];

-

-int 		desired_speed = 11025;

-int 		desired_bits = 16;

-

-int sound_started=0;

-

-cvar_t bgmvolume = {"bgmvolume", "1", true};

-cvar_t volume = {"volume", "0.7", true};

-

-cvar_t nosound = {"nosound", "0"};

-cvar_t precache = {"precache", "1"};

-cvar_t loadas8bit = {"loadas8bit", "0"};

-cvar_t bgmbuffer = {"bgmbuffer", "4096"};

-cvar_t ambient_level = {"ambient_level", "0.3"};

-cvar_t ambient_fade = {"ambient_fade", "100"};

-cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"};

-cvar_t snd_show = {"snd_show", "0"};

-cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true};

-

-

-// ====================================================================

-// User-setable variables

-// ====================================================================

-

-

-//

-// Fake dma is a synchronous faking of the DMA progress used for

-// isolating performance in the renderer.  The fakedma_updates is

-// number of times S_Update() is called per second.

-//

-

-qboolean fakedma = false;

-int fakedma_updates = 15;

-

-

-void S_AmbientOff (void)

-{

-	snd_ambient = false;

-}

-

-

-void S_AmbientOn (void)

-{

-	snd_ambient = true;

-}

-

-

-void S_SoundInfo_f(void)

-{

-	if (!sound_started || !shm)

-	{

-		Con_Printf ("sound system not started\n");

-		return;

-	}

-	

-    Con_Printf("%5d stereo\n", shm->channels - 1);

-    Con_Printf("%5d samples\n", shm->samples);

-    Con_Printf("%5d samplepos\n", shm->samplepos);

-    Con_Printf("%5d samplebits\n", shm->samplebits);

-    Con_Printf("%5d submission_chunk\n", shm->submission_chunk);

-    Con_Printf("%5d speed\n", shm->speed);

-    Con_Printf("0x%x dma buffer\n", shm->buffer);

-	Con_Printf("%5d total_channels\n", total_channels);

-}

-

-

-/*

-================

-S_Startup

-================

-*/

-

-void S_Startup (void)

-{

-	int		rc;

-

-	if (!snd_initialized)

-		return;

-

-	if (!fakedma)

-	{

-		rc = SNDDMA_Init();

-

-		if (!rc)

-		{

-#ifndef	_WIN32

-			Con_Printf("S_Startup: SNDDMA_Init failed.\n");

-#endif

-			sound_started = 0;

-			return;

-		}

-	}

-

-	sound_started = 1;

-}

-

-

-/*

-================

-S_Init

-================

-*/

-void S_Init (void)

-{

-

-//	Con_Printf("\nSound Initialization\n");

-

-	if (COM_CheckParm("-nosound"))

-		return;

-

-	if (COM_CheckParm("-simsound"))

-		fakedma = true;

-

-	Cmd_AddCommand("play", S_Play);

-	Cmd_AddCommand("playvol", S_PlayVol);

-	Cmd_AddCommand("stopsound", S_StopAllSoundsC);

-	Cmd_AddCommand("soundlist", S_SoundList);

-	Cmd_AddCommand("soundinfo", S_SoundInfo_f);

-

-	Cvar_RegisterVariable(&nosound);

-	Cvar_RegisterVariable(&volume);

-	Cvar_RegisterVariable(&precache);

-	Cvar_RegisterVariable(&loadas8bit);

-	Cvar_RegisterVariable(&bgmvolume);

-	Cvar_RegisterVariable(&bgmbuffer);

-	Cvar_RegisterVariable(&ambient_level);

-	Cvar_RegisterVariable(&ambient_fade);

-	Cvar_RegisterVariable(&snd_noextraupdate);

-	Cvar_RegisterVariable(&snd_show);

-	Cvar_RegisterVariable(&_snd_mixahead);

-

-	if (host_parms.memsize < 0x800000)

-	{

-		Cvar_Set ("loadas8bit", "1");

-		Con_Printf ("loading all sounds as 8bit\n");

-	}

-

-

-

-	snd_initialized = true;

-

-	S_Startup ();

-

-	SND_InitScaletable ();

-

-	known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");

-	num_sfx = 0;

-

-// create a piece of DMA memory

-

-	if (fakedma)

-	{

-		shm = (void *) Hunk_AllocName(sizeof(*shm), "shm");

-		shm->splitbuffer = 0;

-		shm->samplebits = 16;

-		shm->speed = 22050;

-		shm->channels = 2;

-		shm->samples = 32768;

-		shm->samplepos = 0;

-		shm->soundalive = true;

-		shm->gamealive = true;

-		shm->submission_chunk = 1;

-		shm->buffer = Hunk_AllocName(1<<16, "shmbuf");

-	}

-

-//	Con_Printf ("Sound sampling rate: %i\n", shm->speed);

-

-	// provides a tick sound until washed clean

-

-//	if (shm->buffer)

-//		shm->buffer[4] = shm->buffer[5] = 0x7f;	// force a pop for debugging

-

-	ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");

-	ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");

-

-	S_StopAllSounds (true);

-}

-

-

-// =======================================================================

-// Shutdown sound engine

-// =======================================================================

-

-void S_Shutdown(void)

-{

-

-	if (!sound_started)

-		return;

-

-	if (shm)

-		shm->gamealive = 0;

-

-	shm = 0;

-	sound_started = 0;

-

-	if (!fakedma)

-	{

-		SNDDMA_Shutdown();

-	}

-}

-

-

-// =======================================================================

-// Load a sound

-// =======================================================================

-

-/*

-==================

-S_FindName

-

-==================

-*/

-sfx_t *S_FindName (char *name)

-{

-	int		i;

-	sfx_t	*sfx;

-

-	if (!name)

-		Sys_Error ("S_FindName: NULL\n");

-

-	if (Q_strlen(name) >= MAX_QPATH)

-		Sys_Error ("Sound name too long: %s", name);

-

-// see if already loaded

-	for (i=0 ; i < num_sfx ; i++)

-		if (!Q_strcmp(known_sfx[i].name, name))

-		{

-			return &known_sfx[i];

-		}

-

-	if (num_sfx == MAX_SFX)

-		Sys_Error ("S_FindName: out of sfx_t");

-	

-	sfx = &known_sfx[i];

-	strcpy (sfx->name, name);

-

-	num_sfx++;

-	

-	return sfx;

-}

-

-

-/*

-==================

-S_TouchSound

-

-==================

-*/

-void S_TouchSound (char *name)

-{

-	sfx_t	*sfx;

-	

-	if (!sound_started)

-		return;

-

-	sfx = S_FindName (name);

-	Cache_Check (&sfx->cache);

-}

-

-/*

-==================

-S_PrecacheSound

-

-==================

-*/

-sfx_t *S_PrecacheSound (char *name)

-{

-	sfx_t	*sfx;

-

-	if (!sound_started || nosound.value)

-		return NULL;

-

-	sfx = S_FindName (name);

-	

-// cache it in

-	if (precache.value)

-		S_LoadSound (sfx);

-	

-	return sfx;

-}

-

-

-//=============================================================================

-

-/*

-=================

-SND_PickChannel

-=================

-*/

-channel_t *SND_PickChannel(int entnum, int entchannel)

-{

-    int ch_idx;

-    int first_to_die;

-    int life_left;

-

-// Check for replacement sound, or find the best one to replace

-    first_to_die = -1;

-    life_left = 0x7fffffff;

-    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)

-    {

-		if (entchannel != 0		// channel 0 never overrides

-		&& channels[ch_idx].entnum == entnum

-		&& (channels[ch_idx].entchannel == entchannel || entchannel == -1) )

-		{	// allways override sound from same entity

-			first_to_die = ch_idx;

-			break;

-		}

-

-		// don't let monster sounds override player sounds

-		if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)

-			continue;

-

-		if (channels[ch_idx].end - paintedtime < life_left)

-		{

-			life_left = channels[ch_idx].end - paintedtime;

-			first_to_die = ch_idx;

-		}

-   }

-

-	if (first_to_die == -1)

-		return NULL;

-

-	if (channels[first_to_die].sfx)

-		channels[first_to_die].sfx = NULL;

-

-    return &channels[first_to_die];    

-}       

-

-/*

-=================

-SND_Spatialize

-=================

-*/

-void SND_Spatialize(channel_t *ch)

-{

-    vec_t dot;

-    vec_t dist;

-    vec_t lscale, rscale, scale;

-    vec3_t source_vec;

-	sfx_t *snd;

-

-// anything coming from the view entity will allways be full volume

-	if (ch->entnum == cl.viewentity)

-	{

-		ch->leftvol = ch->master_vol;

-		ch->rightvol = ch->master_vol;

-		return;

-	}

-

-// calculate stereo seperation and distance attenuation

-

-	snd = ch->sfx;

-	VectorSubtract(ch->origin, listener_origin, source_vec);

-	

-	dist = VectorNormalize(source_vec) * ch->dist_mult;

-	

-	dot = DotProduct(listener_right, source_vec);

-

-	if (shm->channels == 1)

-	{

-		rscale = 1.0;

-		lscale = 1.0;

-	}

-	else

-	{

-		rscale = 1.0 + dot;

-		lscale = 1.0 - dot;

-	}

-

-// add in distance effect

-	scale = (1.0 - dist) * rscale;

-	ch->rightvol = (int) (ch->master_vol * scale);

-	if (ch->rightvol < 0)

-		ch->rightvol = 0;

-

-	scale = (1.0 - dist) * lscale;

-	ch->leftvol = (int) (ch->master_vol * scale);

-	if (ch->leftvol < 0)

-		ch->leftvol = 0;

-}           

-

-

-// =======================================================================

-// Start a sound effect

-// =======================================================================

-

-void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)

-{

-	channel_t *target_chan, *check;

-	sfxcache_t	*sc;

-	int		vol;

-	int		ch_idx;

-	int		skip;

-

-	if (!sound_started)

-		return;

-

-	if (!sfx)

-		return;

-

-	if (nosound.value)

-		return;

-

-	vol = fvol*255;

-

-// pick a channel to play on

-	target_chan = SND_PickChannel(entnum, entchannel);

-	if (!target_chan)

-		return;

-		

-// spatialize

-	memset (target_chan, 0, sizeof(*target_chan));

-	VectorCopy(origin, target_chan->origin);

-	target_chan->dist_mult = attenuation / sound_nominal_clip_dist;

-	target_chan->master_vol = vol;

-	target_chan->entnum = entnum;

-	target_chan->entchannel = entchannel;

-	SND_Spatialize(target_chan);

-

-	if (!target_chan->leftvol && !target_chan->rightvol)

-		return;		// not audible at all

-

-// new channel

-	sc = S_LoadSound (sfx);

-	if (!sc)

-	{

-		target_chan->sfx = NULL;

-		return;		// couldn't load the sound's data

-	}

-

-	target_chan->sfx = sfx;

-	target_chan->pos = 0.0;

-    target_chan->end = paintedtime + sc->length;	

-

-// if an identical sound has also been started this frame, offset the pos

-// a bit to keep it from just making the first one louder

-	check = &channels[NUM_AMBIENTS];

-    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)

-    {

-		if (check == target_chan)

-			continue;

-		if (check->sfx == sfx && !check->pos)

-		{

-			skip = rand () % (int)(0.1*shm->speed);

-			if (skip >= target_chan->end)

-				skip = target_chan->end - 1;

-			target_chan->pos += skip;

-			target_chan->end -= skip;

-			break;

-		}

-		

-	}

-}

-

-void S_StopSound(int entnum, int entchannel)

-{

-	int i;

-

-	for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)

-	{

-		if (channels[i].entnum == entnum

-			&& channels[i].entchannel == entchannel)

-		{

-			channels[i].end = 0;

-			channels[i].sfx = NULL;

-			return;

-		}

-	}

-}

-

-void S_StopAllSounds(qboolean clear)

-{

-	int		i;

-

-	if (!sound_started)

-		return;

-

-	total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;	// no statics

-

-	for (i=0 ; i<MAX_CHANNELS ; i++)

-		if (channels[i].sfx)

-			channels[i].sfx = NULL;

-

-	Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));

-

-	if (clear)

-		S_ClearBuffer ();

-}

-

-void S_StopAllSoundsC (void)

-{

-	S_StopAllSounds (true);

-}

-

-void S_ClearBuffer (void)

-{

-	int		clear;

-		

-#ifdef _WIN32

-	if (!sound_started || !shm || (!shm->buffer && !pDSBuf))

-#else

-	if (!sound_started || !shm || !shm->buffer)

-#endif

-		return;

-

-	if (shm->samplebits == 8)

-		clear = 0x80;

-	else

-		clear = 0;

-

-#ifdef _WIN32

-	if (pDSBuf)

-	{

-		DWORD	dwSize;

-		DWORD	*pData;

-		int		reps;

-		HRESULT	hresult;

-

-		reps = 0;

-

-		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK)

-		{

-			if (hresult != DSERR_BUFFERLOST)

-			{

-				Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");

-				S_Shutdown ();

-				return;

-			}

-

-			if (++reps > 10000)

-			{

-				Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n");

-				S_Shutdown ();

-				return;

-			}

-		}

-

-		Q_memset(pData, clear, shm->samples * shm->samplebits/8);

-

-		pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);

-	

-	}

-	else

-#endif

-	{

-		Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8);

-	}

-}

-

-

-/*

-=================

-S_StaticSound

-=================

-*/

-void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)

-{

-	channel_t	*ss;

-	sfxcache_t		*sc;

-

-	if (!sfx)

-		return;

-

-	if (total_channels == MAX_CHANNELS)

-	{

-		Con_Printf ("total_channels == MAX_CHANNELS\n");

-		return;

-	}

-

-	ss = &channels[total_channels];

-	total_channels++;

-

-	sc = S_LoadSound (sfx);

-	if (!sc)

-		return;

-

-	if (sc->loopstart == -1)

-	{

-		Con_Printf ("Sound %s not looped\n", sfx->name);

-		return;

-	}

-	

-	ss->sfx = sfx;

-	VectorCopy (origin, ss->origin);

-	ss->master_vol = vol;

-	ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;

-    ss->end = paintedtime + sc->length;	

-	

-	SND_Spatialize (ss);

-}

-

-

-//=============================================================================

-

-/*

-===================

-S_UpdateAmbientSounds

-===================

-*/

-void S_UpdateAmbientSounds (void)

-{

-	mleaf_t		*l;

-	float		vol;

-	int			ambient_channel;

-	channel_t	*chan;

-

-	if (!snd_ambient)

-		return;

-

-// calc ambient sound levels

-	if (!cl.worldmodel)

-		return;

-

-	l = Mod_PointInLeaf (listener_origin, cl.worldmodel);

-	if (!l || !ambient_level.value)

-	{

-		for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)

-			channels[ambient_channel].sfx = NULL;

-		return;

-	}

-

-	for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)

-	{

-		chan = &channels[ambient_channel];	

-		chan->sfx = ambient_sfx[ambient_channel];

-	

-		vol = ambient_level.value * l->ambient_sound_level[ambient_channel];

-		if (vol < 8)

-			vol = 0;

-

-	// don't adjust volume too fast

-		if (chan->master_vol < vol)

-		{

-			chan->master_vol += host_frametime * ambient_fade.value;

-			if (chan->master_vol > vol)

-				chan->master_vol = vol;

-		}

-		else if (chan->master_vol > vol)

-		{

-			chan->master_vol -= host_frametime * ambient_fade.value;

-			if (chan->master_vol < vol)

-				chan->master_vol = vol;

-		}

-		

-		chan->leftvol = chan->rightvol = chan->master_vol;

-	}

-}

-

-

-/*

-============

-S_Update

-

-Called once each time through the main loop

-============

-*/

-void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)

-{

-	int			i, j;

-	int			total;

-	channel_t	*ch;

-	channel_t	*combine;

-

-	if (!sound_started || (snd_blocked > 0))

-		return;

-

-	VectorCopy(origin, listener_origin);

-	VectorCopy(forward, listener_forward);

-	VectorCopy(right, listener_right);

-	VectorCopy(up, listener_up);

-	

-// update general area ambient sound sources

-	S_UpdateAmbientSounds ();

-

-	combine = NULL;

-

-// update spatialization for static and dynamic sounds	

-	ch = channels+NUM_AMBIENTS;

-	for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)

-	{

-		if (!ch->sfx)

-			continue;

-		SND_Spatialize(ch);         // respatialize channel

-		if (!ch->leftvol && !ch->rightvol)

-			continue;

-

-	// try to combine static sounds with a previous channel of the same

-	// sound effect so we don't mix five torches every frame

-	

-		if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)

-		{

-		// see if it can just use the last one

-			if (combine && combine->sfx == ch->sfx)

-			{

-				combine->leftvol += ch->leftvol;

-				combine->rightvol += ch->rightvol;

-				ch->leftvol = ch->rightvol = 0;

-				continue;

-			}

-		// search for one

-			combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;

-			for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)

-				if (combine->sfx == ch->sfx)

-					break;

-					

-			if (j == total_channels)

-			{

-				combine = NULL;

-			}

-			else

-			{

-				if (combine != ch)

-				{

-					combine->leftvol += ch->leftvol;

-					combine->rightvol += ch->rightvol;

-					ch->leftvol = ch->rightvol = 0;

-				}

-				continue;

-			}

-		}

-		

-		

-	}

-

-//

-// debugging output

-//

-	if (snd_show.value)

-	{

-		total = 0;

-		ch = channels;

-		for (i=0 ; i<total_channels; i++, ch++)

-			if (ch->sfx && (ch->leftvol || ch->rightvol) )

-			{

-				//Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);

-				total++;

-			}

-		

-		Con_Printf ("----(%i)----\n", total);

-	}

-

-// mix some sound

-	S_Update_();

-}

-

-void GetSoundtime(void)

-{

-	int		samplepos;

-	static	int		buffers;

-	static	int		oldsamplepos;

-	int		fullsamples;

-	

-	fullsamples = shm->samples / shm->channels;

-

-// it is possible to miscount buffers if it has wrapped twice between

-// calls to S_Update.  Oh well.

-	samplepos = SNDDMA_GetDMAPos();

-

-	if (samplepos < oldsamplepos)

-	{

-		buffers++;					// buffer wrapped

-		

-		if (paintedtime > 0x40000000)

-		{	// time to chop things off to avoid 32 bit limits

-			buffers = 0;

-			paintedtime = fullsamples;

-			S_StopAllSounds (true);

-		}

-	}

-	oldsamplepos = samplepos;

-

-	soundtime = buffers*fullsamples + samplepos/shm->channels;

-}

-

-void S_ExtraUpdate (void)

-{

-

-#ifdef _WIN32

-	IN_Accumulate ();

-#endif

-

-	if (snd_noextraupdate.value)

-		return;		// don't pollute timings

-	S_Update_();

-}

-

-

-

-void S_Update_(void)

-{

-	unsigned        endtime;

-	int				samps;

-	

-	if (!sound_started || (snd_blocked > 0))

-		return;

-

-// Updates DMA time

-	GetSoundtime();

-

-// check to make sure that we haven't overshot

-	if (paintedtime < soundtime)

-	{

-		//Con_Printf ("S_Update_ : overflow\n");

-		paintedtime = soundtime;

-	}

-

-// mix ahead of current position

-	endtime = soundtime + _snd_mixahead.value * shm->speed;

-	samps = shm->samples >> (shm->channels-1);

-	if (endtime - soundtime > samps)

-		endtime = soundtime + samps;

-

-#ifdef _WIN32

-// if the buffer was lost or stopped, restore it and/or restart it

-	{

-		DWORD	dwStatus;

-

-		if (pDSBuf)

-		{

-			if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)

-				Con_Printf ("Couldn't get sound buffer status\n");

-			

-			if (dwStatus & DSBSTATUS_BUFFERLOST)

-				pDSBuf->lpVtbl->Restore (pDSBuf);

-			

-			if (!(dwStatus & DSBSTATUS_PLAYING))

-				pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);

-		}

-	}

-#endif

-

-	S_PaintChannels (endtime);

-

-	SNDDMA_Submit ();

-}

-

-/*

-===============================================================================

-

-console functions

-

-===============================================================================

-*/

-

-void S_Play(void)

-{

-	static int hash=345;

-	int 	i;

-	char name[256];

-	sfx_t	*sfx;

-	

-	i = 1;

-	while (i<Cmd_Argc())

-	{

-		if (!Q_strrchr(Cmd_Argv(i), '.'))

-		{

-			Q_strcpy(name, Cmd_Argv(i));

-			Q_strcat(name, ".wav");

-		}

-		else

-			Q_strcpy(name, Cmd_Argv(i));

-		sfx = S_PrecacheSound(name);

-		S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);

-		i++;

-	}

-}

-

-void S_PlayVol(void)

-{

-	static int hash=543;

-	int i;

-	float vol;

-	char name[256];

-	sfx_t	*sfx;

-	

-	i = 1;

-	while (i<Cmd_Argc())

-	{

-		if (!Q_strrchr(Cmd_Argv(i), '.'))

-		{

-			Q_strcpy(name, Cmd_Argv(i));

-			Q_strcat(name, ".wav");

-		}

-		else

-			Q_strcpy(name, Cmd_Argv(i));

-		sfx = S_PrecacheSound(name);

-		vol = Q_atof(Cmd_Argv(i+1));

-		S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);

-		i+=2;

-	}

-}

-

-void S_SoundList(void)

-{

-	int		i;

-	sfx_t	*sfx;

-	sfxcache_t	*sc;

-	int		size, total;

-

-	total = 0;

-	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)

-	{

-		sc = Cache_Check (&sfx->cache);

-		if (!sc)

-			continue;

-		size = sc->length*sc->width*(sc->stereo+1);

-		total += size;

-		if (sc->loopstart >= 0)

-			Con_Printf ("L");

-		else

-			Con_Printf (" ");

-		Con_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);

-	}

-	Con_Printf ("Total resident: %i\n", total);

-}

-

-

-void S_LocalSound (char *sound)

-{

-	sfx_t	*sfx;

-

-	if (nosound.value)

-		return;

-	if (!sound_started)

-		return;

-		

-	sfx = S_PrecacheSound (sound);

-	if (!sfx)

-	{

-		Con_Printf ("S_LocalSound: can't cache %s\n", sound);

-		return;

-	}

-	S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);

-}

-

-

-void S_ClearPrecache (void)

-{

-}

-

-

-void S_BeginPrecaching (void)

-{

-}

-

-

-void S_EndPrecaching (void)

-{

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// snd_dma.c -- main control for any streaming sound output device
+
+#include "quakedef.h"
+
+#ifdef _WIN32
+#include "winquake.h"
+#endif
+
+void S_Play(void);
+void S_PlayVol(void);
+void S_SoundList(void);
+void S_Update_();
+void S_StopAllSounds(qboolean clear);
+void S_StopAllSoundsC(void);
+
+// QuakeWorld hack...
+#define	viewentity	playernum+1
+
+// =======================================================================
+// Internal sound data & structures
+// =======================================================================
+
+channel_t   channels[MAX_CHANNELS];
+int			total_channels;
+
+int				snd_blocked = 0;
+static qboolean	snd_ambient = 1;
+qboolean		snd_initialized = false;
+
+// pointer should go away
+volatile dma_t  *shm = 0;
+volatile dma_t sn;
+
+vec3_t		listener_origin;
+vec3_t		listener_forward;
+vec3_t		listener_right;
+vec3_t		listener_up;
+vec_t		sound_nominal_clip_dist=1000.0;
+
+int			soundtime;		// sample PAIRS
+int   		paintedtime; 	// sample PAIRS
+
+
+#define	MAX_SFX		512
+sfx_t		*known_sfx;		// hunk allocated [MAX_SFX]
+int			num_sfx;
+
+sfx_t		*ambient_sfx[NUM_AMBIENTS];
+
+int 		desired_speed = 11025;
+int 		desired_bits = 16;
+
+int sound_started=0;
+
+cvar_t bgmvolume = CVAR3("bgmvolume", "1", true);
+cvar_t volume = CVAR3("volume", "0.7", true);
+
+cvar_t nosound = CVAR2("nosound", "0");
+cvar_t precache = CVAR2("precache", "1");
+cvar_t loadas8bit = CVAR2("loadas8bit", "0");
+cvar_t bgmbuffer = CVAR2("bgmbuffer", "4096");
+cvar_t ambient_level = CVAR2("ambient_level", "0.3");
+cvar_t ambient_fade = CVAR2("ambient_fade", "100");
+cvar_t snd_noextraupdate = CVAR2("snd_noextraupdate", "0");
+cvar_t snd_show = CVAR2("snd_show", "0");
+cvar_t _snd_mixahead = CVAR3("_snd_mixahead", "0.1", true);
+
+
+// ====================================================================
+// User-setable variables
+// ====================================================================
+
+
+//
+// Fake dma is a synchronous faking of the DMA progress used for
+// isolating performance in the renderer.  The fakedma_updates is
+// number of times S_Update() is called per second.
+//
+
+qboolean fakedma = false;
+int fakedma_updates = 15;
+
+
+void S_AmbientOff (void)
+{
+	snd_ambient = false;
+}
+
+
+void S_AmbientOn (void)
+{
+	snd_ambient = true;
+}
+
+
+void S_SoundInfo_f(void)
+{
+	if (!sound_started || !shm)
+	{
+		Con_Printf ("sound system not started\n");
+		return;
+	}
+	
+    Con_Printf("%5d stereo\n", shm->channels - 1);
+    Con_Printf("%5d samples\n", shm->samples);
+    Con_Printf("%5d samplepos\n", shm->samplepos);
+    Con_Printf("%5d samplebits\n", shm->samplebits);
+    Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
+    Con_Printf("%5d speed\n", shm->speed);
+    Con_Printf("0x%x dma buffer\n", shm->buffer);
+	Con_Printf("%5d total_channels\n", total_channels);
+}
+
+
+/*
+================
+S_Startup
+================
+*/
+
+void S_Startup (void)
+{
+	int		rc;
+
+	if (!snd_initialized)
+		return;
+
+	if (!fakedma)
+	{
+		rc = SNDDMA_Init();
+
+		if (!rc)
+		{
+#ifndef	_WIN32
+			Con_Printf("S_Startup: SNDDMA_Init failed.\n");
+#endif
+			sound_started = 0;
+			return;
+		}
+	}
+
+	sound_started = 1;
+}
+
+
+/*
+================
+S_Init
+================
+*/
+void S_Init (void)
+{
+
+//	Con_Printf("\nSound Initialization\n");
+
+	if (COM_CheckParm("-nosound"))
+		return;
+
+	if (COM_CheckParm("-simsound"))
+		fakedma = true;
+
+	Cmd_AddCommand("play", S_Play);
+	Cmd_AddCommand("playvol", S_PlayVol);
+	Cmd_AddCommand("stopsound", S_StopAllSoundsC);
+	Cmd_AddCommand("soundlist", S_SoundList);
+	Cmd_AddCommand("soundinfo", S_SoundInfo_f);
+
+	Cvar_RegisterVariable(&nosound);
+	Cvar_RegisterVariable(&volume);
+	Cvar_RegisterVariable(&precache);
+	Cvar_RegisterVariable(&loadas8bit);
+	Cvar_RegisterVariable(&bgmvolume);
+	Cvar_RegisterVariable(&bgmbuffer);
+	Cvar_RegisterVariable(&ambient_level);
+	Cvar_RegisterVariable(&ambient_fade);
+	Cvar_RegisterVariable(&snd_noextraupdate);
+	Cvar_RegisterVariable(&snd_show);
+	Cvar_RegisterVariable(&_snd_mixahead);
+
+	if (host_parms.memsize < 0x800000)
+	{
+		Cvar_Set ("loadas8bit", "1");
+		Con_Printf ("loading all sounds as 8bit\n");
+	}
+
+
+
+	snd_initialized = true;
+
+	S_Startup ();
+
+	SND_InitScaletable ();
+
+	known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");
+	num_sfx = 0;
+
+// create a piece of DMA memory
+
+	if (fakedma)
+	{
+		shm = (void *) Hunk_AllocName(sizeof(*shm), "shm");
+		shm->splitbuffer = 0;
+		shm->samplebits = 16;
+		shm->speed = 22050;
+		shm->channels = 2;
+		shm->samples = 32768;
+		shm->samplepos = 0;
+		shm->soundalive = true;
+		shm->gamealive = true;
+		shm->submission_chunk = 1;
+		shm->buffer = Hunk_AllocName(1<<16, "shmbuf");
+	}
+
+//	Con_Printf ("Sound sampling rate: %i\n", shm->speed);
+
+	// provides a tick sound until washed clean
+
+//	if (shm->buffer)
+//		shm->buffer[4] = shm->buffer[5] = 0x7f;	// force a pop for debugging
+
+	ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");
+	ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");
+
+	S_StopAllSounds (true);
+}
+
+
+// =======================================================================
+// Shutdown sound engine
+// =======================================================================
+
+void S_Shutdown(void)
+{
+
+	if (!sound_started)
+		return;
+
+	if (shm)
+		shm->gamealive = 0;
+
+	shm = 0;
+	sound_started = 0;
+
+	if (!fakedma)
+	{
+		SNDDMA_Shutdown();
+	}
+}
+
+
+// =======================================================================
+// Load a sound
+// =======================================================================
+
+/*
+==================
+S_FindName
+
+==================
+*/
+sfx_t *S_FindName (char *name)
+{
+	int		i;
+	sfx_t	*sfx;
+
+	if (!name)
+		Sys_Error ("S_FindName: NULL\n");
+
+	if (Q_strlen(name) >= MAX_QPATH)
+		Sys_Error ("Sound name too long: %s", name);
+
+// see if already loaded
+	for (i=0 ; i < num_sfx ; i++)
+		if (!Q_strcmp(known_sfx[i].name, name))
+		{
+			return &known_sfx[i];
+		}
+
+	if (num_sfx == MAX_SFX)
+		Sys_Error ("S_FindName: out of sfx_t");
+	
+	sfx = &known_sfx[i];
+	strcpy (sfx->name, name);
+
+	num_sfx++;
+	
+	return sfx;
+}
+
+
+/*
+==================
+S_TouchSound
+
+==================
+*/
+void S_TouchSound (char *name)
+{
+	sfx_t	*sfx;
+	
+	if (!sound_started)
+		return;
+
+	sfx = S_FindName (name);
+	Cache_Check (&sfx->cache);
+}
+
+/*
+==================
+S_PrecacheSound
+
+==================
+*/
+sfx_t *S_PrecacheSound (char *name)
+{
+	sfx_t	*sfx;
+
+	if (!sound_started || nosound.value)
+		return NULL;
+
+	sfx = S_FindName (name);
+	
+// cache it in
+	if (precache.value)
+		S_LoadSound (sfx);
+	
+	return sfx;
+}
+
+
+//=============================================================================
+
+/*
+=================
+SND_PickChannel
+=================
+*/
+channel_t *SND_PickChannel(int entnum, int entchannel)
+{
+    int ch_idx;
+    int first_to_die;
+    int life_left;
+
+// Check for replacement sound, or find the best one to replace
+    first_to_die = -1;
+    life_left = 0x7fffffff;
+    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
+    {
+		if (entchannel != 0		// channel 0 never overrides
+		&& channels[ch_idx].entnum == entnum
+		&& (channels[ch_idx].entchannel == entchannel || entchannel == -1) )
+		{	// allways override sound from same entity
+			first_to_die = ch_idx;
+			break;
+		}
+
+		// don't let monster sounds override player sounds
+		if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)
+			continue;
+
+		if (channels[ch_idx].end - paintedtime < life_left)
+		{
+			life_left = channels[ch_idx].end - paintedtime;
+			first_to_die = ch_idx;
+		}
+   }
+
+	if (first_to_die == -1)
+		return NULL;
+
+	if (channels[first_to_die].sfx)
+		channels[first_to_die].sfx = NULL;
+
+    return &channels[first_to_die];    
+}       
+
+/*
+=================
+SND_Spatialize
+=================
+*/
+void SND_Spatialize(channel_t *ch)
+{
+    vec_t dot;
+    vec_t dist;
+    vec_t lscale, rscale, scale;
+    vec3_t source_vec;
+	sfx_t *snd;
+
+// anything coming from the view entity will allways be full volume
+	if (ch->entnum == cl.viewentity)
+	{
+		ch->leftvol = ch->master_vol;
+		ch->rightvol = ch->master_vol;
+		return;
+	}
+
+// calculate stereo seperation and distance attenuation
+
+	snd = ch->sfx;
+	VectorSubtract(ch->origin, listener_origin, source_vec);
+	
+	dist = VectorNormalize(source_vec) * ch->dist_mult;
+	
+	dot = DotProduct(listener_right, source_vec);
+
+	if (shm->channels == 1)
+	{
+		rscale = 1.0;
+		lscale = 1.0;
+	}
+	else
+	{
+		rscale = 1.0 + dot;
+		lscale = 1.0 - dot;
+	}
+
+// add in distance effect
+	scale = (1.0 - dist) * rscale;
+	ch->rightvol = (int) (ch->master_vol * scale);
+	if (ch->rightvol < 0)
+		ch->rightvol = 0;
+
+	scale = (1.0 - dist) * lscale;
+	ch->leftvol = (int) (ch->master_vol * scale);
+	if (ch->leftvol < 0)
+		ch->leftvol = 0;
+}           
+
+
+// =======================================================================
+// Start a sound effect
+// =======================================================================
+
+void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
+{
+	channel_t *target_chan, *check;
+	sfxcache_t	*sc;
+	int		vol;
+	int		ch_idx;
+	int		skip;
+
+	if (!sound_started)
+		return;
+
+	if (!sfx)
+		return;
+
+	if (nosound.value)
+		return;
+
+	vol = fvol*255;
+
+// pick a channel to play on
+	target_chan = SND_PickChannel(entnum, entchannel);
+	if (!target_chan)
+		return;
+		
+// spatialize
+	memset (target_chan, 0, sizeof(*target_chan));
+	VectorCopy(origin, target_chan->origin);
+	target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
+	target_chan->master_vol = vol;
+	target_chan->entnum = entnum;
+	target_chan->entchannel = entchannel;
+	SND_Spatialize(target_chan);
+
+	if (!target_chan->leftvol && !target_chan->rightvol)
+		return;		// not audible at all
+
+// new channel
+	sc = S_LoadSound (sfx);
+	if (!sc)
+	{
+		target_chan->sfx = NULL;
+		return;		// couldn't load the sound's data
+	}
+
+	target_chan->sfx = sfx;
+	target_chan->pos = 0.0;
+    target_chan->end = paintedtime + sc->length;	
+
+// if an identical sound has also been started this frame, offset the pos
+// a bit to keep it from just making the first one louder
+	check = &channels[NUM_AMBIENTS];
+    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
+    {
+		if (check == target_chan)
+			continue;
+		if (check->sfx == sfx && !check->pos)
+		{
+			skip = rand () % (int)(0.1*shm->speed);
+			if (skip >= target_chan->end)
+				skip = target_chan->end - 1;
+			target_chan->pos += skip;
+			target_chan->end -= skip;
+			break;
+		}
+		
+	}
+}
+
+void S_StopSound(int entnum, int entchannel)
+{
+	int i;
+
+	for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)
+	{
+		if (channels[i].entnum == entnum
+			&& channels[i].entchannel == entchannel)
+		{
+			channels[i].end = 0;
+			channels[i].sfx = NULL;
+			return;
+		}
+	}
+}
+
+void S_StopAllSounds(qboolean clear)
+{
+	int		i;
+
+	if (!sound_started)
+		return;
+
+	total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;	// no statics
+
+	for (i=0 ; i<MAX_CHANNELS ; i++)
+		if (channels[i].sfx)
+			channels[i].sfx = NULL;
+
+	Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
+
+	if (clear)
+		S_ClearBuffer ();
+}
+
+void S_StopAllSoundsC (void)
+{
+	S_StopAllSounds (true);
+}
+
+void S_ClearBuffer (void)
+{
+	int		clear;
+		
+#ifdef _WIN32
+	if (!sound_started || !shm || (!shm->buffer && !pDSBuf))
+#else
+	if (!sound_started || !shm || !shm->buffer)
+#endif
+		return;
+
+	if (shm->samplebits == 8)
+		clear = 0x80;
+	else
+		clear = 0;
+
+#ifdef _WIN32
+	if (pDSBuf)
+	{
+		DWORD	dwSize;
+		DWORD	*pData;
+		int		reps;
+		HRESULT	hresult;
+
+		reps = 0;
+
+		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK)
+		{
+			if (hresult != DSERR_BUFFERLOST)
+			{
+				Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");
+				S_Shutdown ();
+				return;
+			}
+
+			if (++reps > 10000)
+			{
+				Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n");
+				S_Shutdown ();
+				return;
+			}
+		}
+
+		Q_memset(pData, clear, shm->samples * shm->samplebits/8);
+
+		pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);
+	
+	}
+	else
+#endif
+	{
+		Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8);
+	}
+}
+
+
+/*
+=================
+S_StaticSound
+=================
+*/
+void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
+{
+	channel_t	*ss;
+	sfxcache_t		*sc;
+
+	if (!sfx)
+		return;
+
+	if (total_channels == MAX_CHANNELS)
+	{
+		Con_Printf ("total_channels == MAX_CHANNELS\n");
+		return;
+	}
+
+	ss = &channels[total_channels];
+	total_channels++;
+
+	sc = S_LoadSound (sfx);
+	if (!sc)
+		return;
+
+	if (sc->loopstart == -1)
+	{
+		Con_Printf ("Sound %s not looped\n", sfx->name);
+		return;
+	}
+	
+	ss->sfx = sfx;
+	VectorCopy (origin, ss->origin);
+	ss->master_vol = vol;
+	ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
+    ss->end = paintedtime + sc->length;	
+	
+	SND_Spatialize (ss);
+}
+
+
+//=============================================================================
+
+/*
+===================
+S_UpdateAmbientSounds
+===================
+*/
+void S_UpdateAmbientSounds (void)
+{
+	mleaf_t		*l;
+	float		vol;
+	int			ambient_channel;
+	channel_t	*chan;
+
+	if (!snd_ambient)
+		return;
+
+// calc ambient sound levels
+	if (!cl.worldmodel)
+		return;
+
+	l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
+	if (!l || !ambient_level.value)
+	{
+		for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
+			channels[ambient_channel].sfx = NULL;
+		return;
+	}
+
+	for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
+	{
+		chan = &channels[ambient_channel];	
+		chan->sfx = ambient_sfx[ambient_channel];
+	
+		vol = ambient_level.value * l->ambient_sound_level[ambient_channel];
+		if (vol < 8)
+			vol = 0;
+
+	// don't adjust volume too fast
+		if (chan->master_vol < vol)
+		{
+			chan->master_vol += host_frametime * ambient_fade.value;
+			if (chan->master_vol > vol)
+				chan->master_vol = vol;
+		}
+		else if (chan->master_vol > vol)
+		{
+			chan->master_vol -= host_frametime * ambient_fade.value;
+			if (chan->master_vol < vol)
+				chan->master_vol = vol;
+		}
+		
+		chan->leftvol = chan->rightvol = chan->master_vol;
+	}
+}
+
+
+/*
+============
+S_Update
+
+Called once each time through the main loop
+============
+*/
+void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
+{
+	int			i, j;
+	int			total;
+	channel_t	*ch;
+	channel_t	*combine;
+
+	if (!sound_started || (snd_blocked > 0))
+		return;
+
+	VectorCopy(origin, listener_origin);
+	VectorCopy(forward, listener_forward);
+	VectorCopy(right, listener_right);
+	VectorCopy(up, listener_up);
+	
+// update general area ambient sound sources
+	S_UpdateAmbientSounds ();
+
+	combine = NULL;
+
+// update spatialization for static and dynamic sounds	
+	ch = channels+NUM_AMBIENTS;
+	for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
+	{
+		if (!ch->sfx)
+			continue;
+		SND_Spatialize(ch);         // respatialize channel
+		if (!ch->leftvol && !ch->rightvol)
+			continue;
+
+	// try to combine static sounds with a previous channel of the same
+	// sound effect so we don't mix five torches every frame
+	
+		if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
+		{
+		// see if it can just use the last one
+			if (combine && combine->sfx == ch->sfx)
+			{
+				combine->leftvol += ch->leftvol;
+				combine->rightvol += ch->rightvol;
+				ch->leftvol = ch->rightvol = 0;
+				continue;
+			}
+		// search for one
+			combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
+			for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
+				if (combine->sfx == ch->sfx)
+					break;
+					
+			if (j == total_channels)
+			{
+				combine = NULL;
+			}
+			else
+			{
+				if (combine != ch)
+				{
+					combine->leftvol += ch->leftvol;
+					combine->rightvol += ch->rightvol;
+					ch->leftvol = ch->rightvol = 0;
+				}
+				continue;
+			}
+		}
+		
+		
+	}
+
+//
+// debugging output
+//
+	if (snd_show.value)
+	{
+		total = 0;
+		ch = channels;
+		for (i=0 ; i<total_channels; i++, ch++)
+			if (ch->sfx && (ch->leftvol || ch->rightvol) )
+			{
+				//Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
+				total++;
+			}
+		
+		Con_Printf ("----(%i)----\n", total);
+	}
+
+// mix some sound
+	S_Update_();
+}
+
+void GetSoundtime(void)
+{
+	int		samplepos;
+	static	int		buffers;
+	static	int		oldsamplepos;
+	int		fullsamples;
+	
+	fullsamples = shm->samples / shm->channels;
+
+// it is possible to miscount buffers if it has wrapped twice between
+// calls to S_Update.  Oh well.
+	samplepos = SNDDMA_GetDMAPos();
+
+	if (samplepos < oldsamplepos)
+	{
+		buffers++;					// buffer wrapped
+		
+		if (paintedtime > 0x40000000)
+		{	// time to chop things off to avoid 32 bit limits
+			buffers = 0;
+			paintedtime = fullsamples;
+			S_StopAllSounds (true);
+		}
+	}
+	oldsamplepos = samplepos;
+
+	soundtime = buffers*fullsamples + samplepos/shm->channels;
+}
+
+void S_ExtraUpdate (void)
+{
+
+#ifdef _WIN32
+	IN_Accumulate ();
+#endif
+
+	if (snd_noextraupdate.value)
+		return;		// don't pollute timings
+	S_Update_();
+}
+
+
+
+void S_Update_(void)
+{
+	unsigned        endtime;
+	int				samps;
+	
+	if (!sound_started || (snd_blocked > 0))
+		return;
+
+// Updates DMA time
+	GetSoundtime();
+
+// check to make sure that we haven't overshot
+	if (paintedtime < soundtime)
+	{
+		//Con_Printf ("S_Update_ : overflow\n");
+		paintedtime = soundtime;
+	}
+
+// mix ahead of current position
+	endtime = soundtime + _snd_mixahead.value * shm->speed;
+	samps = shm->samples >> (shm->channels-1);
+	if ((int)(endtime - soundtime) > samps)
+		endtime = soundtime + samps;
+
+#ifdef _WIN32
+// if the buffer was lost or stopped, restore it and/or restart it
+	{
+		DWORD	dwStatus;
+
+		if (pDSBuf)
+		{
+			if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)
+				Con_Printf ("Couldn't get sound buffer status\n");
+			
+			if (dwStatus & DSBSTATUS_BUFFERLOST)
+				pDSBuf->lpVtbl->Restore (pDSBuf);
+			
+			if (!(dwStatus & DSBSTATUS_PLAYING))
+				pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
+		}
+	}
+#endif
+
+	S_PaintChannels (endtime);
+
+	SNDDMA_Submit ();
+}
+
+/*
+===============================================================================
+
+console functions
+
+===============================================================================
+*/
+
+void S_Play(void)
+{
+	static int hash=345;
+	int 	i;
+	char name[256];
+	sfx_t	*sfx;
+	
+	i = 1;
+	while (i<Cmd_Argc())
+	{
+		if (!Q_strrchr(Cmd_Argv(i), '.'))
+		{
+			Q_strcpy(name, Cmd_Argv(i));
+			Q_strcat(name, ".wav");
+		}
+		else
+			Q_strcpy(name, Cmd_Argv(i));
+		sfx = S_PrecacheSound(name);
+		S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);
+		i++;
+	}
+}
+
+void S_PlayVol(void)
+{
+	static int hash=543;
+	int i;
+	float vol;
+	char name[256];
+	sfx_t	*sfx;
+	
+	i = 1;
+	while (i<Cmd_Argc())
+	{
+		if (!Q_strrchr(Cmd_Argv(i), '.'))
+		{
+			Q_strcpy(name, Cmd_Argv(i));
+			Q_strcat(name, ".wav");
+		}
+		else
+			Q_strcpy(name, Cmd_Argv(i));
+		sfx = S_PrecacheSound(name);
+		vol = Q_atof(Cmd_Argv(i+1));
+		S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);
+		i+=2;
+	}
+}
+
+void S_SoundList(void)
+{
+	int		i;
+	sfx_t	*sfx;
+	sfxcache_t	*sc;
+	int		size, total;
+
+	total = 0;
+	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
+	{
+		sc = Cache_Check (&sfx->cache);
+		if (!sc)
+			continue;
+		size = sc->length*sc->width*(sc->stereo+1);
+		total += size;
+		if (sc->loopstart >= 0)
+			Con_Printf ("L");
+		else
+			Con_Printf (" ");
+		Con_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);
+	}
+	Con_Printf ("Total resident: %i\n", total);
+}
+
+
+void S_LocalSound (char *sound)
+{
+	sfx_t	*sfx;
+
+	if (nosound.value)
+		return;
+	if (!sound_started)
+		return;
+		
+	sfx = S_PrecacheSound (sound);
+	if (!sfx)
+	{
+		Con_Printf ("S_LocalSound: can't cache %s\n", sound);
+		return;
+	}
+	S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);
+}
+
+
+void S_ClearPrecache (void)
+{
+}
+
+
+void S_BeginPrecaching (void)
+{
+}
+
+
+void S_EndPrecaching (void)
+{
+}
+
diff --git a/quake/src/QW/client/snd_linux.c b/quake/src/QW/client/snd_linux.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/snd_mem.c b/quake/src/QW/client/snd_mem.c
old mode 100644
new mode 100755
index e385137..a38ab39
--- a/quake/src/QW/client/snd_mem.c
+++ b/quake/src/QW/client/snd_mem.c
@@ -1,343 +1,343 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// snd_mem.c: sound caching

-

-#include "quakedef.h"

-

-int			cache_full_cycle;

-

-byte *S_Alloc (int size);

-

-/*

-================

-ResampleSfx

-================

-*/

-void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)

-{

-	int		outcount;

-	int		srcsample;

-	float	stepscale;

-	int		i;

-	int		sample, samplefrac, fracstep;

-	sfxcache_t	*sc;

-	

-	sc = Cache_Check (&sfx->cache);

-	if (!sc)

-		return;

-

-	stepscale = (float)inrate / shm->speed;	// this is usually 0.5, 1, or 2

-

-	outcount = sc->length / stepscale;

-	sc->length = outcount;

-	if (sc->loopstart != -1)

-		sc->loopstart = sc->loopstart / stepscale;

-

-	sc->speed = shm->speed;

-	if (loadas8bit.value)

-		sc->width = 1;

-	else

-		sc->width = inwidth;

-	sc->stereo = 0;

-

-// resample / decimate to the current source rate

-

-	if (stepscale == 1 && inwidth == 1 && sc->width == 1)

-	{

-// fast special case

-		for (i=0 ; i<outcount ; i++)

-			((signed char *)sc->data)[i]

-			= (int)( (unsigned char)(data[i]) - 128);

-	}

-	else

-	{

-// general case

-		samplefrac = 0;

-		fracstep = stepscale*256;

-		for (i=0 ; i<outcount ; i++)

-		{

-			srcsample = samplefrac >> 8;

-			samplefrac += fracstep;

-			if (inwidth == 2)

-				sample = LittleShort ( ((short *)data)[srcsample] );

-			else

-				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;

-			if (sc->width == 2)

-				((short *)sc->data)[i] = sample;

-			else

-				((signed char *)sc->data)[i] = sample >> 8;

-		}

-	}

-}

-

-//=============================================================================

-

-/*

-==============

-S_LoadSound

-==============

-*/

-sfxcache_t *S_LoadSound (sfx_t *s)

-{

-    char	namebuffer[256];

-	byte	*data;

-	wavinfo_t	info;

-	int		len;

-	float	stepscale;

-	sfxcache_t	*sc;

-	byte	stackbuf[1*1024];		// avoid dirtying the cache heap

-

-// see if still in memory

-	sc = Cache_Check (&s->cache);

-	if (sc)

-		return sc;

-

-//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);

-// load it in

-    Q_strcpy(namebuffer, "sound/");

-    Q_strcat(namebuffer, s->name);

-

-//	Con_Printf ("loading %s\n",namebuffer);

-

-	data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));

-

-	if (!data)

-	{

-		Con_Printf ("Couldn't load %s\n", namebuffer);

-		return NULL;

-	}

-

-	info = GetWavinfo (s->name, data, com_filesize);

-	if (info.channels != 1)

-	{

-		Con_Printf ("%s is a stereo sample\n",s->name);

-		return NULL;

-	}

-

-	stepscale = (float)info.rate / shm->speed;	

-	len = info.samples / stepscale;

-

-	len = len * info.width * info.channels;

-

-	sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);

-	if (!sc)

-		return NULL;

-	

-	sc->length = info.samples;

-	sc->loopstart = info.loopstart;

-	sc->speed = info.rate;

-	sc->width = info.width;

-	sc->stereo = info.channels;

-

-	ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);

-

-	return sc;

-}

-

-

-

-/*

-===============================================================================

-

-WAV loading

-

-===============================================================================

-*/

-

-

-byte	*data_p;

-byte 	*iff_end;

-byte 	*last_chunk;

-byte 	*iff_data;

-int 	iff_chunk_len;

-

-

-short GetLittleShort(void)

-{

-	short val = 0;

-	val = *data_p;

-	val = val + (*(data_p+1)<<8);

-	data_p += 2;

-	return val;

-}

-

-int GetLittleLong(void)

-{

-	int val = 0;

-	val = *data_p;

-	val = val + (*(data_p+1)<<8);

-	val = val + (*(data_p+2)<<16);

-	val = val + (*(data_p+3)<<24);

-	data_p += 4;

-	return val;

-}

-

-void FindNextChunk(char *name)

-{

-	while (1)

-	{

-		data_p=last_chunk;

-

-		if (data_p >= iff_end)

-		{	// didn't find the chunk

-			data_p = NULL;

-			return;

-		}

-		

-		data_p += 4;

-		iff_chunk_len = GetLittleLong();

-		if (iff_chunk_len < 0)

-		{

-			data_p = NULL;

-			return;

-		}

-//		if (iff_chunk_len > 1024*1024)

-//			Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);

-		data_p -= 8;

-		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );

-		if (!Q_strncmp(data_p, name, 4))

-			return;

-	}

-}

-

-void FindChunk(char *name)

-{

-	last_chunk = iff_data;

-	FindNextChunk (name);

-}

-

-

-#if 0

-void DumpChunks(void)

-{

-	char	str[5];

-	

-	str[4] = 0;

-	data_p=iff_data;

-	do

-	{

-		memcpy (str, data_p, 4);

-		data_p += 4;

-		iff_chunk_len = GetLittleLong();

-		Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);

-		data_p += (iff_chunk_len + 1) & ~1;

-	} while (data_p < iff_end);

-}

-#endif

-

-/*

-============

-GetWavinfo

-============

-*/

-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)

-{

-	wavinfo_t	info;

-	int     i;

-	int     format;

-	int		samples;

-

-	memset (&info, 0, sizeof(info));

-

-	if (!wav)

-		return info;

-		

-	iff_data = wav;

-	iff_end = wav + wavlength;

-

-// find "RIFF" chunk

-	FindChunk("RIFF");

-	if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))

-	{

-		Con_Printf("Missing RIFF/WAVE chunks\n");

-		return info;

-	}

-

-// get "fmt " chunk

-	iff_data = data_p + 12;

-// DumpChunks ();

-

-	FindChunk("fmt ");

-	if (!data_p)

-	{

-		Con_Printf("Missing fmt chunk\n");

-		return info;

-	}

-	data_p += 8;

-	format = GetLittleShort();

-	if (format != 1)

-	{

-		Con_Printf("Microsoft PCM format only\n");

-		return info;

-	}

-

-	info.channels = GetLittleShort();

-	info.rate = GetLittleLong();

-	data_p += 4+2;

-	info.width = GetLittleShort() / 8;

-

-// get cue chunk

-	FindChunk("cue ");

-	if (data_p)

-	{

-		data_p += 32;

-		info.loopstart = GetLittleLong();

-//		Con_Printf("loopstart=%d\n", sfx->loopstart);

-

-	// if the next chunk is a LIST chunk, look for a cue length marker

-		FindNextChunk ("LIST");

-		if (data_p)

-		{

-			if (!strncmp (data_p + 28, "mark", 4))

-			{	// this is not a proper parse, but it works with cooledit...

-				data_p += 24;

-				i = GetLittleLong ();	// samples in loop

-				info.samples = info.loopstart + i;

-//				Con_Printf("looped length: %i\n", i);

-			}

-		}

-	}

-	else

-		info.loopstart = -1;

-

-// find data chunk

-	FindChunk("data");

-	if (!data_p)

-	{

-		Con_Printf("Missing data chunk\n");

-		return info;

-	}

-

-	data_p += 4;

-	samples = GetLittleLong () / info.width;

-

-	if (info.samples)

-	{

-		if (samples < info.samples)

-			Sys_Error ("Sound %s has a bad loop length", name);

-	}

-	else

-		info.samples = samples;

-

-	info.dataofs = data_p - wav;

-	

-	return info;

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// snd_mem.c: sound caching
+
+#include "quakedef.h"
+
+int			cache_full_cycle;
+
+byte *S_Alloc (int size);
+
+/*
+================
+ResampleSfx
+================
+*/
+void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
+{
+	int		outcount;
+	int		srcsample;
+	float	stepscale;
+	int		i;
+	int		sample, samplefrac, fracstep;
+	sfxcache_t	*sc;
+	
+	sc = Cache_Check (&sfx->cache);
+	if (!sc)
+		return;
+
+	stepscale = (float)inrate / shm->speed;	// this is usually 0.5, 1, or 2
+
+	outcount = sc->length / stepscale;
+	sc->length = outcount;
+	if (sc->loopstart != -1)
+		sc->loopstart = sc->loopstart / stepscale;
+
+	sc->speed = shm->speed;
+	if (loadas8bit.value)
+		sc->width = 1;
+	else
+		sc->width = inwidth;
+	sc->stereo = 0;
+
+// resample / decimate to the current source rate
+
+	if (stepscale == 1 && inwidth == 1 && sc->width == 1)
+	{
+// fast special case
+		for (i=0 ; i<outcount ; i++)
+			((signed char *)sc->data)[i]
+			= (int)( (unsigned char)(data[i]) - 128);
+	}
+	else
+	{
+// general case
+		samplefrac = 0;
+		fracstep = stepscale*256;
+		for (i=0 ; i<outcount ; i++)
+		{
+			srcsample = samplefrac >> 8;
+			samplefrac += fracstep;
+			if (inwidth == 2)
+				sample = LittleShort ( ((short *)data)[srcsample] );
+			else
+				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
+			if (sc->width == 2)
+				((short *)sc->data)[i] = sample;
+			else
+				((signed char *)sc->data)[i] = sample >> 8;
+		}
+	}
+}
+
+//=============================================================================
+
+/*
+==============
+S_LoadSound
+==============
+*/
+sfxcache_t *S_LoadSound (sfx_t *s)
+{
+    char	namebuffer[256];
+	byte	*data;
+	wavinfo_t	info;
+	int		len;
+	float	stepscale;
+	sfxcache_t	*sc;
+	byte	stackbuf[1*1024];		// avoid dirtying the cache heap
+
+// see if still in memory
+	sc = Cache_Check (&s->cache);
+	if (sc)
+		return sc;
+
+//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
+// load it in
+    Q_strcpy(namebuffer, "sound/");
+    Q_strcat(namebuffer, s->name);
+
+//	Con_Printf ("loading %s\n",namebuffer);
+
+	data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
+
+	if (!data)
+	{
+		Con_Printf ("Couldn't load %s\n", namebuffer);
+		return NULL;
+	}
+
+	info = GetWavinfo (s->name, data, com_filesize);
+	if (info.channels != 1)
+	{
+		Con_Printf ("%s is a stereo sample\n",s->name);
+		return NULL;
+	}
+
+	stepscale = (float)info.rate / shm->speed;	
+	len = info.samples / stepscale;
+
+	len = len * info.width * info.channels;
+
+	sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
+	if (!sc)
+		return NULL;
+	
+	sc->length = info.samples;
+	sc->loopstart = info.loopstart;
+	sc->speed = info.rate;
+	sc->width = info.width;
+	sc->stereo = info.channels;
+
+	ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
+
+	return sc;
+}
+
+
+
+/*
+===============================================================================
+
+WAV loading
+
+===============================================================================
+*/
+
+
+byte	*data_p;
+byte 	*iff_end;
+byte 	*last_chunk;
+byte 	*iff_data;
+int 	iff_chunk_len;
+
+
+short GetLittleShort(void)
+{
+	short val = 0;
+	val = *data_p;
+	val = val + (*(data_p+1)<<8);
+	data_p += 2;
+	return val;
+}
+
+int GetLittleLong(void)
+{
+	int val = 0;
+	val = *data_p;
+	val = val + (*(data_p+1)<<8);
+	val = val + (*(data_p+2)<<16);
+	val = val + (*(data_p+3)<<24);
+	data_p += 4;
+	return val;
+}
+
+void FindNextChunk(char *name)
+{
+	while (1)
+	{
+		data_p=last_chunk;
+
+		if (data_p >= iff_end)
+		{	// didn't find the chunk
+			data_p = NULL;
+			return;
+		}
+		
+		data_p += 4;
+		iff_chunk_len = GetLittleLong();
+		if (iff_chunk_len < 0)
+		{
+			data_p = NULL;
+			return;
+		}
+//		if (iff_chunk_len > 1024*1024)
+//			Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
+		data_p -= 8;
+		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
+		if (!Q_strncmp((char*) data_p, name, 4))
+			return;
+	}
+}
+
+void FindChunk(char *name)
+{
+	last_chunk = iff_data;
+	FindNextChunk (name);
+}
+
+
+#if 0
+void DumpChunks(void)
+{
+	char	str[5];
+	
+	str[4] = 0;
+	data_p=iff_data;
+	do
+	{
+		memcpy (str, data_p, 4);
+		data_p += 4;
+		iff_chunk_len = GetLittleLong();
+		Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
+		data_p += (iff_chunk_len + 1) & ~1;
+	} while (data_p < iff_end);
+}
+#endif
+
+/*
+============
+GetWavinfo
+============
+*/
+wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
+{
+	wavinfo_t	info;
+	int     i;
+	int     format;
+	int		samples;
+
+	memset (&info, 0, sizeof(info));
+
+	if (!wav)
+		return info;
+		
+	iff_data = wav;
+	iff_end = wav + wavlength;
+
+// find "RIFF" chunk
+	FindChunk("RIFF");
+	if (!(data_p && !Q_strncmp((char*) (data_p+8), "WAVE", 4)))
+	{
+		Con_Printf("Missing RIFF/WAVE chunks\n");
+		return info;
+	}
+
+// get "fmt " chunk
+	iff_data = data_p + 12;
+// DumpChunks ();
+
+	FindChunk("fmt ");
+	if (!data_p)
+	{
+		Con_Printf("Missing fmt chunk\n");
+		return info;
+	}
+	data_p += 8;
+	format = GetLittleShort();
+	if (format != 1)
+	{
+		Con_Printf("Microsoft PCM format only\n");
+		return info;
+	}
+
+	info.channels = GetLittleShort();
+	info.rate = GetLittleLong();
+	data_p += 4+2;
+	info.width = GetLittleShort() / 8;
+
+// get cue chunk
+	FindChunk("cue ");
+	if (data_p)
+	{
+		data_p += 32;
+		info.loopstart = GetLittleLong();
+//		Con_Printf("loopstart=%d\n", sfx->loopstart);
+
+	// if the next chunk is a LIST chunk, look for a cue length marker
+		FindNextChunk ("LIST");
+		if (data_p)
+		{
+			if (!strncmp ((char*) (data_p + 28), "mark", 4))
+			{	// this is not a proper parse, but it works with cooledit...
+				data_p += 24;
+				i = GetLittleLong ();	// samples in loop
+				info.samples = info.loopstart + i;
+//				Con_Printf("looped length: %i\n", i);
+			}
+		}
+	}
+	else
+		info.loopstart = -1;
+
+// find data chunk
+	FindChunk("data");
+	if (!data_p)
+	{
+		Con_Printf("Missing data chunk\n");
+		return info;
+	}
+
+	data_p += 4;
+	samples = GetLittleLong () / info.width;
+
+	if (info.samples)
+	{
+		if (samples < info.samples)
+			Sys_Error ("Sound %s has a bad loop length", name);
+	}
+	else
+		info.samples = samples;
+
+	info.dataofs = data_p - wav;
+	
+	return info;
+}
+
diff --git a/quake/src/QW/client/snd_mix.c b/quake/src/QW/client/snd_mix.c
old mode 100644
new mode 100755
index c040494..fa71931
--- a/quake/src/QW/client/snd_mix.c
+++ b/quake/src/QW/client/snd_mix.c
@@ -357,7 +357,7 @@
 		

 	lscale = snd_scaletable[ch->leftvol >> 3];

 	rscale = snd_scaletable[ch->rightvol >> 3];

-	sfx = (signed char *)sc->data + ch->pos;

+	sfx = (unsigned char *)sc->data + ch->pos;

 

 	for (i=0 ; i<count ; i++)

 	{

diff --git a/quake/src/QW/client/snd_mixa.asm b/quake/src/QW/client/snd_mixa.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/snd_mixa.s b/quake/src/QW/client/snd_mixa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/snd_win.c b/quake/src/QW/client/snd_win.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sound.h b/quake/src/QW/client/sound.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/spritegn.h b/quake/src/QW/client/spritegn.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/surf16.asm b/quake/src/QW/client/surf16.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/surf16.s b/quake/src/QW/client/surf16.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/surf8.asm b/quake/src/QW/client/surf8.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/surf8.s b/quake/src/QW/client/surf8.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sys.h b/quake/src/QW/client/sys.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sys_android.c b/quake/src/QW/client/sys_android.c
new file mode 100755
index 0000000..b832945
--- /dev/null
+++ b/quake/src/QW/client/sys_android.c
@@ -0,0 +1,427 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+// Based on sys_linux.c
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+// #include <sys/ipc.h>
+// #include <sys/shm.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "quakedef.h"
+
+int noconinput = 0;
+int nostdout = 0;
+
+char *basedir = "/sdcard/data/quake";
+char *cachedir = "/tmp";
+
+cvar_t  sys_linerefresh = CVAR2("sys_linerefresh","0");// set for entity display
+
+// =======================================================================
+// General routines
+// =======================================================================
+
+void Sys_DebugNumber(int y, int val)
+{
+}
+
+/*
+void Sys_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		text[1024];
+	
+	va_start (argptr,fmt);
+	vsprintf (text,fmt,argptr);
+	va_end (argptr);
+	fprintf(stderr, "%s", text);
+	
+	Con_Print (text);
+}
+
+void Sys_Printf (char *fmt, ...)
+{
+
+    va_list     argptr;
+    char        text[1024], *t_p;
+    int         l, r;
+
+    if (nostdout)
+        return;
+
+    va_start (argptr,fmt);
+    vsprintf (text,fmt,argptr);
+    va_end (argptr);
+
+    l = strlen(text);
+    t_p = text;
+
+// make sure everything goes through, even though we are non-blocking
+    while (l)
+    {
+        r = write (1, text, l);
+        if (r != l)
+            sleep (0);
+        if (r > 0)
+        {
+            t_p += r;
+            l -= r;
+        }
+    }
+
+}
+*/
+
+void Sys_Printf (char *fmt, ...)
+{
+	va_list		argptr;
+	char		text[2048];
+	unsigned char		*p;
+
+	va_start (argptr,fmt);
+	vsprintf (text,fmt,argptr);
+	va_end (argptr);
+
+	if (strlen(text) > sizeof(text))
+		Sys_Error("memory overwrite in Sys_Printf");
+
+    if (nostdout)
+        return;
+
+	for (p = (unsigned char *)text; *p; p++)
+		if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
+			printf("[%02x]", *p);
+		else
+			putc(*p, stdout);
+}
+
+void Sys_Quit (void)
+{
+	Host_Shutdown();
+	printf("Sys_Quit - exiting.");
+    // fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
+	exit(0);
+}
+
+void Sys_Init(void)
+{
+#if id386
+	Sys_SetFPCW();
+#endif
+}
+
+void Sys_Error (char *error, ...)
+{ 
+    va_list     argptr;
+    char        string[1024];
+
+// change stdin to non blocking
+    // fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
+    
+    va_start (argptr,error);
+    vsprintf (string,error,argptr);
+    va_end (argptr);
+	fprintf(stderr, "Error: %s\n", string);
+
+	Host_Shutdown ();
+	printf("Sys_Error - exiting.");
+	exit (1);
+
+} 
+
+void Sys_Warn (char *warning, ...)
+{ 
+    va_list     argptr;
+    char        string[1024];
+    
+    va_start (argptr,warning);
+    vsprintf (string,warning,argptr);
+    va_end (argptr);
+	fprintf(stderr, "Warning: %s", string);
+} 
+
+/*
+============
+Sys_FileTime
+
+returns -1 if not present
+============
+*/
+int	Sys_FileTime (char *path)
+{
+	struct	stat	buf;
+	
+	if (stat (path,&buf) == -1)
+		return -1;
+	
+	return buf.st_mtime;
+}
+
+
+void Sys_mkdir (char *path)
+{
+    mkdir (path, 0777);
+}
+
+int Sys_FileOpenRead (char *path, int *handle)
+{
+	int	h;
+	struct stat	fileinfo;
+    
+	
+	h = open (path, O_RDONLY, 0666);
+	*handle = h;
+	if (h == -1)
+		return -1;
+	
+	if (fstat (h,&fileinfo) == -1)
+		Sys_Error ("Error fstating %s", path);
+
+	return fileinfo.st_size;
+}
+
+int Sys_FileOpenWrite (char *path)
+{
+	int     handle;
+
+	umask (0);
+	
+	handle = open(path,O_RDWR | O_CREAT | O_TRUNC
+	, 0666);
+
+	if (handle == -1)
+		Sys_Error ("Error opening %s: %s", path,strerror(errno));
+
+	return handle;
+}
+
+int Sys_FileWrite (int handle, void *src, int count)
+{
+	return write (handle, src, count);
+}
+
+void Sys_FileClose (int handle)
+{
+	close (handle);
+}
+
+void Sys_FileSeek (int handle, int position)
+{
+	lseek (handle, position, SEEK_SET);
+}
+
+int Sys_FileRead (int handle, void *dest, int count)
+{
+    return read (handle, dest, count);
+}
+
+void Sys_DebugLog(char *file, char *fmt, ...)
+{
+    va_list argptr; 
+    static char data[1024];
+    int fd;
+    
+    va_start(argptr, fmt);
+    vsprintf(data, fmt, argptr);
+    va_end(argptr);
+//    fd = open(file, O_WRONLY | O_BINARY | O_CREAT | O_APPEND, 0666);
+    fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
+    write(fd, data, strlen(data));
+    close(fd);
+}
+
+void Sys_EditFile(char *filename)
+{
+
+	char cmd[256];
+	char *term;
+	char *editor;
+
+	term = getenv("TERM");
+	if (term && !strcmp(term, "xterm"))
+	{
+		editor = getenv("VISUAL");
+		if (!editor)
+			editor = getenv("EDITOR");
+		if (!editor)
+			editor = getenv("EDIT");
+		if (!editor)
+			editor = "vi";
+		sprintf(cmd, "xterm -e %s %s", editor, filename);
+		system(cmd);
+	}
+
+}
+
+double Sys_DoubleTime (void)
+{
+    struct timeval tp;
+    struct timezone tzp; 
+    static int      secbase; 
+    
+    gettimeofday(&tp, &tzp);  
+
+    if (!secbase)
+    {
+        secbase = tp.tv_sec;
+        return tp.tv_usec/1000000.0;
+    }
+
+    return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
+}
+
+// =======================================================================
+// Sleeps for microseconds
+// =======================================================================
+
+static volatile int oktogo;
+
+void alarm_handler(int x)
+{
+	oktogo=1;
+}
+
+void Sys_LineRefresh(void)
+{
+}
+
+void floating_point_exception_handler(int whatever)
+{
+//	Sys_Warn("floating point exception\n");
+	signal(SIGFPE, floating_point_exception_handler);
+}
+
+char *Sys_ConsoleInput(void)
+{
+#if 0
+    static char text[256];
+    int     len;
+
+	if (cls.state == ca_dedicated) {
+		len = read (0, text, sizeof(text));
+		if (len < 1)
+			return NULL;
+		text[len-1] = 0;    // rip off the /n and terminate
+
+		return text;
+	}
+#endif
+	return NULL;
+}
+
+#if !id386
+void Sys_HighFPPrecision (void)
+{
+}
+
+void Sys_LowFPPrecision (void)
+{
+}
+#endif
+
+int		skipframes;
+
+// The following APIs are called from the Java activity
+
+int gAndroidQuitting = 0;
+
+double g_oldtime;
+
+extern int scr_width;
+extern int scr_height;
+
+void AndroidInit(int width, int height)
+{
+	quakeparms_t parms;
+	int j;
+	int c = 0;
+	char* v[] = {"quake", (char*) 0};
+	
+	scr_width = width;
+	scr_height = height;
+
+//	static char cwd[1024];
+
+//	signal(SIGFPE, floating_point_exception_handler);
+//  signal(SIGFPE, SIG_IGN);
+
+	memset(&parms, 0, sizeof(parms));
+
+	COM_InitArgv(c, v);
+	parms.argc = com_argc;
+	parms.argv = com_argv;
+
+	parms.memsize = 16*1024*1024;
+
+	j = COM_CheckParm("-mem");
+	if (j)
+		parms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
+	parms.membase = malloc (parms.memsize);
+
+	parms.basedir = basedir;
+// caching is disabled by default, use -cachedir to enable
+//	parms.cachedir = cachedir;
+
+#if 0 // FNDELAY not implemented
+	noconinput = COM_CheckParm("-noconinput");
+	if (!noconinput)
+		fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+#endif
+
+	if (COM_CheckParm("-nostdout"))
+		nostdout = 1;
+
+	Sys_Init();
+
+    Host_Init(&parms);
+
+    g_oldtime = Sys_DoubleTime ();
+}
+
+void AndroidStep()
+{
+	double time, newtime;
+	// find time spent rendering last frame
+	newtime = Sys_DoubleTime ();
+	time = newtime - g_oldtime;
+
+	Host_Frame(time);
+	g_oldtime = newtime;
+}
+
+int AndroidQuiting()
+{
+	return gAndroidQuitting;
+}
diff --git a/quake/src/QW/client/sys_dosa.s b/quake/src/QW/client/sys_dosa.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sys_linux.c b/quake/src/QW/client/sys_linux.c
old mode 100644
new mode 100755
index 9ff8a8b..60c62e5
--- a/quake/src/QW/client/sys_linux.c
+++ b/quake/src/QW/client/sys_linux.c
@@ -44,7 +44,7 @@
 char *basedir = ".";

 char *cachedir = "/tmp";

 

-cvar_t  sys_linerefresh = {"sys_linerefresh","0"};// set for entity display

+cvar_t  sys_linerefresh = CVAR2("sys_linerefresh","0");// set for entity display

 

 // =======================================================================

 // General routines

diff --git a/quake/src/QW/client/sys_null.c b/quake/src/QW/client/sys_null.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sys_win.c b/quake/src/QW/client/sys_win.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sys_wina.asm b/quake/src/QW/client/sys_wina.asm
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/sys_wina.s b/quake/src/QW/client/sys_wina.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/vid.h b/quake/src/QW/client/vid.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/vid_null.c b/quake/src/QW/client/vid_null.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/vid_svgalib.c b/quake/src/QW/client/vid_svgalib.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/vid_win.c b/quake/src/QW/client/vid_win.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/vid_x.c b/quake/src/QW/client/vid_x.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/view.c b/quake/src/QW/client/view.c
old mode 100644
new mode 100755
index 5605049..2b7a56f
--- a/quake/src/QW/client/view.c
+++ b/quake/src/QW/client/view.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // view.c -- player eye positioning
 
 #include "quakedef.h"
@@ -31,39 +31,39 @@
 
 */
 
-cvar_t	lcd_x = {"lcd_x", "0"};	// FIXME: make this work sometime...
+cvar_t	lcd_x = CVAR2("lcd_x", "0");	// FIXME: make this work sometime...
 
-cvar_t	cl_rollspeed = {"cl_rollspeed", "200"};
-cvar_t	cl_rollangle = {"cl_rollangle", "2.0"};
+cvar_t	cl_rollspeed = CVAR2("cl_rollspeed", "200");
+cvar_t	cl_rollangle = CVAR2("cl_rollangle", "2.0");
 
-cvar_t	cl_bob = {"cl_bob","0.02", false};
-cvar_t	cl_bobcycle = {"cl_bobcycle","0.6", false};
-cvar_t	cl_bobup = {"cl_bobup","0.5", false};
+cvar_t	cl_bob = CVAR3("cl_bob","0.02", false);
+cvar_t	cl_bobcycle = CVAR3("cl_bobcycle","0.6", false);
+cvar_t	cl_bobup = CVAR3("cl_bobup","0.5", false);
 
-cvar_t	v_kicktime = {"v_kicktime", "0.5", false};
-cvar_t	v_kickroll = {"v_kickroll", "0.6", false};
-cvar_t	v_kickpitch = {"v_kickpitch", "0.6", false};
+cvar_t	v_kicktime = CVAR3("v_kicktime", "0.5", false);
+cvar_t	v_kickroll = CVAR3("v_kickroll", "0.6", false);
+cvar_t	v_kickpitch = CVAR3("v_kickpitch", "0.6", false);
 
-cvar_t	v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
-cvar_t	v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
-cvar_t	v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
-cvar_t	v_iyaw_level = {"v_iyaw_level", "0.3", false};
-cvar_t	v_iroll_level = {"v_iroll_level", "0.1", false};
-cvar_t	v_ipitch_level = {"v_ipitch_level", "0.3", false};
+cvar_t	v_iyaw_cycle = CVAR3("v_iyaw_cycle", "2", false);
+cvar_t	v_iroll_cycle = CVAR3("v_iroll_cycle", "0.5", false);
+cvar_t	v_ipitch_cycle = CVAR3("v_ipitch_cycle", "1", false);
+cvar_t	v_iyaw_level = CVAR3("v_iyaw_level", "0.3", false);
+cvar_t	v_iroll_level = CVAR3("v_iroll_level", "0.1", false);
+cvar_t	v_ipitch_level = CVAR3("v_ipitch_level", "0.3", false);
 
-cvar_t	v_idlescale = {"v_idlescale", "0", false};
+cvar_t	v_idlescale = CVAR3("v_idlescale", "0", false);
 
-cvar_t	crosshair = {"crosshair", "0", true};
-cvar_t	crosshaircolor = {"crosshaircolor", "79", true};
+cvar_t	crosshair = CVAR3("crosshair", "0", true);
+cvar_t	crosshaircolor = CVAR3("crosshaircolor", "79", true);
 
-cvar_t  cl_crossx = {"cl_crossx", "0", true};
-cvar_t  cl_crossy = {"cl_crossy", "0", true};
-

+cvar_t  cl_crossx = CVAR3("cl_crossx", "0", true);
+cvar_t  cl_crossy = CVAR3("cl_crossy", "0", true);
+
 #ifdef GLQUAKE
-cvar_t	gl_cshiftpercent = {"gl_cshiftpercent", "100", false};

-#endif

-

-cvar_t  v_contentblend = {"v_contentblend", "1", false};
+cvar_t	gl_cshiftpercent = CVAR3("gl_cshiftpercent", "100", false);
+#endif
+
+cvar_t  v_contentblend = CVAR3("v_contentblend", "1", false);
 
 float	v_dmg_time, v_dmg_roll, v_dmg_pitch;
 
@@ -145,8 +145,8 @@
 //=============================================================================
 
 
-cvar_t	v_centermove = {"v_centermove", "0.15", false};
-cvar_t	v_centerspeed = {"v_centerspeed","500"};
+cvar_t	v_centermove = CVAR3("v_centermove", "0.15", false);
+cvar_t	v_centerspeed = CVAR2("v_centerspeed","500");
 
 
 void V_StartPitchDrift (void)
@@ -262,7 +262,7 @@
 cshift_t	cshift_slime = { {0,25,5}, 150 };
 cshift_t	cshift_lava = { {255,80,0}, 150 };
 
-cvar_t		v_gamma = {"gamma", "1", true};
+cvar_t		v_gamma = CVAR3("gamma", "1", true);
 
 byte		gammatable[256];	// palette is sent through this
 
@@ -420,11 +420,11 @@
 =============
 */
 void V_SetContentsColor (int contents)
-{

-	if (!v_contentblend.value) {

-		cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;

-		return;

-	}

+{
+	if (!v_contentblend.value) {
+		cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
+		return;
+	}
 
 	switch (contents)
 	{
@@ -1044,15 +1044,15 @@
 	Cvar_RegisterVariable (&v_iroll_level);
 	Cvar_RegisterVariable (&v_ipitch_level);
 
-	Cvar_RegisterVariable (&v_contentblend);

-

+	Cvar_RegisterVariable (&v_contentblend);
+
 	Cvar_RegisterVariable (&v_idlescale);
 	Cvar_RegisterVariable (&crosshaircolor);
 	Cvar_RegisterVariable (&crosshair);
 	Cvar_RegisterVariable (&cl_crossx);
-	Cvar_RegisterVariable (&cl_crossy);

+	Cvar_RegisterVariable (&cl_crossy);
 #ifdef GLQUAKE
-	Cvar_RegisterVariable (&gl_cshiftpercent);

+	Cvar_RegisterVariable (&gl_cshiftpercent);
 #endif
 
 	Cvar_RegisterVariable (&cl_rollspeed);
diff --git a/quake/src/QW/client/view.h b/quake/src/QW/client/view.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/wad.c b/quake/src/QW/client/wad.c
old mode 100644
new mode 100755
index e0a3e51..6337107
--- a/quake/src/QW/client/wad.c
+++ b/quake/src/QW/client/wad.c
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // wad.c
 
 #include "quakedef.h"
@@ -88,7 +88,7 @@
 	infotableofs = LittleLong(header->infotableofs);
 	wad_lumps = (lumpinfo_t *)(wad_base + infotableofs);
 	
-	for (i=0, lump_p = wad_lumps ; i<wad_numlumps ; i++,lump_p++)
+	for (i=0, lump_p = wad_lumps ; i< (unsigned) wad_numlumps ; i++,lump_p++)
 	{
 		lump_p->filepos = LittleLong(lump_p->filepos);
 		lump_p->size = LittleLong(lump_p->size);
diff --git a/quake/src/QW/client/wad.h b/quake/src/QW/client/wad.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/winquake.aps b/quake/src/QW/client/winquake.aps
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/client/winquake.h b/quake/src/QW/client/winquake.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/winquake.rc b/quake/src/QW/client/winquake.rc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/zone.c b/quake/src/QW/client/zone.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/client/zone.h b/quake/src/QW/client/zone.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/cmds.txt b/quake/src/QW/cmds.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/docs/glqwcl-readme.txt b/quake/src/QW/docs/glqwcl-readme.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/docs/qwcl-readme.txt b/quake/src/QW/docs/qwcl-readme.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/docs/readme.qwcl b/quake/src/QW/docs/readme.qwcl
old mode 100644
new mode 100755
diff --git a/quake/src/QW/docs/readme.qwsv b/quake/src/QW/docs/readme.qwsv
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/d3d.h b/quake/src/QW/dxsdk/sdk/inc/d3d.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/d3dcaps.h b/quake/src/QW/dxsdk/sdk/inc/d3dcaps.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/d3drm.h b/quake/src/QW/dxsdk/sdk/inc/d3drm.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/d3drmdef.h b/quake/src/QW/dxsdk/sdk/inc/d3drmdef.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/d3drmobj.h b/quake/src/QW/dxsdk/sdk/inc/d3drmobj.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/d3drmwin.h b/quake/src/QW/dxsdk/sdk/inc/d3drmwin.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/d3dtypes.h b/quake/src/QW/dxsdk/sdk/inc/d3dtypes.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/ddraw.h b/quake/src/QW/dxsdk/sdk/inc/ddraw.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/dinput.h b/quake/src/QW/dxsdk/sdk/inc/dinput.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/dplay.h b/quake/src/QW/dxsdk/sdk/inc/dplay.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/dsetup.h b/quake/src/QW/dxsdk/sdk/inc/dsetup.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/dsound.h b/quake/src/QW/dxsdk/sdk/inc/dsound.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/inc/fastfile.h b/quake/src/QW/dxsdk/sdk/inc/fastfile.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/dxsdk/sdk/lib/dinput.lib b/quake/src/QW/dxsdk/sdk/lib/dinput.lib
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/dxsdk/sdk/lib/dxguid.lib b/quake/src/QW/dxsdk/sdk/lib/dxguid.lib
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/fixskins.sh b/quake/src/QW/fixskins.sh
old mode 100644
new mode 100755
diff --git a/quake/src/QW/gas2masm/gas2masm.001 b/quake/src/QW/gas2masm/gas2masm.001
old mode 100644
new mode 100755
diff --git a/quake/src/QW/gas2masm/gas2masm.c b/quake/src/QW/gas2masm/gas2masm.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/gas2masm/gas2masm.dsp b/quake/src/QW/gas2masm/gas2masm.dsp
old mode 100644
new mode 100755
diff --git a/quake/src/QW/gas2masm/gas2masm.mak b/quake/src/QW/gas2masm/gas2masm.mak
old mode 100644
new mode 100755
diff --git a/quake/src/QW/gas2masm/gas2masm.mdp b/quake/src/QW/gas2masm/gas2masm.mdp
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/gas2masm/gas2masm.plg b/quake/src/QW/gas2masm/gas2masm.plg
old mode 100644
new mode 100755
diff --git a/quake/src/QW/glqwcl.3dfxgl b/quake/src/QW/glqwcl.3dfxgl
old mode 100644
new mode 100755
diff --git a/quake/src/QW/glqwcl.spec.sh b/quake/src/QW/glqwcl.spec.sh
old mode 100644
new mode 100755
diff --git a/quake/src/QW/makezip b/quake/src/QW/makezip
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/progs/buttons.qc b/quake/src/QW/progs/buttons.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/client.qc b/quake/src/QW/progs/client.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/combat.qc b/quake/src/QW/progs/combat.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/defs.qc b/quake/src/QW/progs/defs.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/doors.qc b/quake/src/QW/progs/doors.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/files.dat b/quake/src/QW/progs/files.dat
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/items.qc b/quake/src/QW/progs/items.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/misc.qc b/quake/src/QW/progs/misc.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/models.qc b/quake/src/QW/progs/models.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/plats.qc b/quake/src/QW/progs/plats.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/player.qc b/quake/src/QW/progs/player.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/progdefs.h b/quake/src/QW/progs/progdefs.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/progs.src b/quake/src/QW/progs/progs.src
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/qwprogs.dat b/quake/src/QW/progs/qwprogs.dat
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/progs/server.qc b/quake/src/QW/progs/server.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/spectate.qc b/quake/src/QW/progs/spectate.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/sprites.qc b/quake/src/QW/progs/sprites.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/subs.qc b/quake/src/QW/progs/subs.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/triggers.qc b/quake/src/QW/progs/triggers.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/weapons.qc b/quake/src/QW/progs/weapons.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/progs/world.qc b/quake/src/QW/progs/world.qc
old mode 100644
new mode 100755
diff --git a/quake/src/QW/quake.gif b/quake/src/QW/quake.gif
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/quakeworld.bmp b/quake/src/QW/quakeworld.bmp
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/qw.dsw b/quake/src/QW/qw.dsw
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qw.ncb b/quake/src/QW/qw.ncb
deleted file mode 100644
index 91b7188..0000000
--- a/quake/src/QW/qw.ncb
+++ /dev/null
Binary files differ
diff --git a/quake/src/QW/qw.opt b/quake/src/QW/qw.opt
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/qw2do.txt b/quake/src/QW/qw2do.txt
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/qwchangelog.txt b/quake/src/QW/qwchangelog.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwcl.spec.sh b/quake/src/QW/qwcl.spec.sh
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwcl.x11.spec.sh b/quake/src/QW/qwcl.x11.spec.sh
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwfwd/misc.c b/quake/src/QW/qwfwd/misc.c
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/qwfwd/qwfwd.001 b/quake/src/QW/qwfwd/qwfwd.001
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwfwd/qwfwd.c b/quake/src/QW/qwfwd/qwfwd.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwfwd/qwfwd.dsp b/quake/src/QW/qwfwd/qwfwd.dsp
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwfwd/qwfwd.dsw b/quake/src/QW/qwfwd/qwfwd.dsw
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwfwd/qwfwd.plg b/quake/src/QW/qwfwd/qwfwd.plg
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwrlnote.txt b/quake/src/QW/qwrlnote.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/qwsv.spec.sh b/quake/src/QW/qwsv.spec.sh
old mode 100644
new mode 100755
diff --git a/quake/src/QW/release233_notes.txt b/quake/src/QW/release233_notes.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/scitech/include/debug.h b/quake/src/QW/scitech/include/debug.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/scitech/include/mgldos.h b/quake/src/QW/scitech/include/mgldos.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/scitech/include/mglwin.h b/quake/src/QW/scitech/include/mglwin.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/scitech/include/mgraph.h b/quake/src/QW/scitech/include/mgraph.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/scitech/lib/win32/vc/mgllt.lib b/quake/src/QW/scitech/lib/win32/vc/mgllt.lib
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/server/asm_i386.h b/quake/src/QW/server/asm_i386.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/makefile b/quake/src/QW/server/makefile
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/math.s b/quake/src/QW/server/math.s
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/model.c b/quake/src/QW/server/model.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/move.txt b/quake/src/QW/server/move.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/newnet.txt b/quake/src/QW/server/newnet.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/notes.txt b/quake/src/QW/server/notes.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/pr_cmds.c b/quake/src/QW/server/pr_cmds.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/pr_comp.h b/quake/src/QW/server/pr_comp.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/pr_edict.c b/quake/src/QW/server/pr_edict.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/pr_exec.c b/quake/src/QW/server/pr_exec.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/profile.txt b/quake/src/QW/server/profile.txt
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/progdefs.h b/quake/src/QW/server/progdefs.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/progs.h b/quake/src/QW/server/progs.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/quakeasm.h b/quake/src/QW/server/quakeasm.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/qwsv.dsp b/quake/src/QW/server/qwsv.dsp
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/qwsv.dsw b/quake/src/QW/server/qwsv.dsw
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/qwsv.mak b/quake/src/QW/server/qwsv.mak
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/qwsv.mdp b/quake/src/QW/server/qwsv.mdp
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/QW/server/qwsv.plg b/quake/src/QW/server/qwsv.plg
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/qwsvdef.h b/quake/src/QW/server/qwsvdef.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/server.h b/quake/src/QW/server/server.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_ccmds.c b/quake/src/QW/server/sv_ccmds.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_ents.c b/quake/src/QW/server/sv_ents.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_init.c b/quake/src/QW/server/sv_init.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_main.c b/quake/src/QW/server/sv_main.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_move.c b/quake/src/QW/server/sv_move.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_nchan.c b/quake/src/QW/server/sv_nchan.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_phys.c b/quake/src/QW/server/sv_phys.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_send.c b/quake/src/QW/server/sv_send.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sv_user.c b/quake/src/QW/server/sv_user.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sys.h b/quake/src/QW/server/sys.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sys_unix.c b/quake/src/QW/server/sys_unix.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/sys_win.c b/quake/src/QW/server/sys_win.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/world.c b/quake/src/QW/server/world.c
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/world.h b/quake/src/QW/server/world.h
old mode 100644
new mode 100755
diff --git a/quake/src/QW/server/worlda.s b/quake/src/QW/server/worlda.s
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/cd_audio.c b/quake/src/WinQuake/cd_audio.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/cd_audio.c
rename to quake/src/WinQuake/cd_audio.cpp
diff --git a/quake/src/WinQuake/cd_linux.c b/quake/src/WinQuake/cd_linux.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/cd_linux.c
rename to quake/src/WinQuake/cd_linux.cpp
diff --git a/quake/src/WinQuake/cd_null.c b/quake/src/WinQuake/cd_null.cpp
old mode 100644
new mode 100755
similarity index 99%
rename from quake/src/WinQuake/cd_null.c
rename to quake/src/WinQuake/cd_null.cpp
index 98f2e2e..c78da42
--- a/quake/src/WinQuake/cd_null.c
+++ b/quake/src/WinQuake/cd_null.cpp
@@ -52,4 +52,4 @@
 

 void CDAudio_Shutdown(void)

 {

-}
\ No newline at end of file
+}

diff --git a/quake/src/WinQuake/cd_win.c b/quake/src/WinQuake/cd_win.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/cd_win.c
rename to quake/src/WinQuake/cd_win.cpp
diff --git a/quake/src/WinQuake/chase.c b/quake/src/WinQuake/chase.cpp
old mode 100644
new mode 100755
similarity index 91%
rename from quake/src/WinQuake/chase.c
rename to quake/src/WinQuake/chase.cpp
index d986ad0..1ccd494
--- a/quake/src/WinQuake/chase.c
+++ b/quake/src/WinQuake/chase.cpp
@@ -21,10 +21,10 @@
 

 #include "quakedef.h"

 

-cvar_t	chase_back = {"chase_back", "100"};

-cvar_t	chase_up = {"chase_up", "16"};

-cvar_t	chase_right = {"chase_right", "0"};

-cvar_t	chase_active = {"chase_active", "0"};

+cvar_t	chase_back = CVAR2("chase_back", "100");

+cvar_t	chase_up = CVAR2("chase_up", "16");

+cvar_t	chase_right = CVAR2("chase_right", "0");

+cvar_t	chase_active = CVAR2("chase_active", "0");

 

 vec3_t	chase_pos;

 vec3_t	chase_angles;

diff --git a/quake/src/WinQuake/cl_demo.c b/quake/src/WinQuake/cl_demo.cpp
old mode 100644
new mode 100755
similarity index 92%
rename from quake/src/WinQuake/cl_demo.c
rename to quake/src/WinQuake/cl_demo.cpp
index c025264..f3cbf5b
--- a/quake/src/WinQuake/cl_demo.c
+++ b/quake/src/WinQuake/cl_demo.cpp
@@ -1,367 +1,379 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-#include "quakedef.h"

-

-void CL_FinishTimeDemo (void);

-

-/*

-==============================================================================

-

-DEMO CODE

-

-When a demo is playing back, all NET_SendMessages are skipped, and

-NET_GetMessages are read from the demo file.

-

-Whenever cl.time gets past the last received message, another message is

-read from the demo file.

-==============================================================================

-*/

-

-/*

-==============

-CL_StopPlayback

-

-Called when a demo file runs out, or the user starts a game

-==============

-*/

-void CL_StopPlayback (void)

-{

-	if (!cls.demoplayback)

-		return;

-

-	fclose (cls.demofile);

-	cls.demoplayback = false;

-	cls.demofile = NULL;

-	cls.state = ca_disconnected;

-

-	if (cls.timedemo)

-		CL_FinishTimeDemo ();

-}

-

-/*

-====================

-CL_WriteDemoMessage

-

-Dumps the current net message, prefixed by the length and view angles

-====================

-*/

-void CL_WriteDemoMessage (void)

-{

-	int		len;

-	int		i;

-	float	f;

-

-	len = LittleLong (net_message.cursize);

-	fwrite (&len, 4, 1, cls.demofile);

-	for (i=0 ; i<3 ; i++)

-	{

-		f = LittleFloat (cl.viewangles[i]);

-		fwrite (&f, 4, 1, cls.demofile);

-	}

-	fwrite (net_message.data, net_message.cursize, 1, cls.demofile);

-	fflush (cls.demofile);

-}

-

-/*

-====================

-CL_GetMessage

-

-Handles recording and playback of demos, on top of NET_ code

-====================

-*/

-int CL_GetMessage (void)

-{

-	int		r, i;

-	float	f;

-	

-	if	(cls.demoplayback)

-	{

-	// decide if it is time to grab the next message		

-		if (cls.signon == SIGNONS)	// allways grab until fully connected

-		{

-			if (cls.timedemo)

-			{

-				if (host_framecount == cls.td_lastframe)

-					return 0;		// allready read this frame's message

-				cls.td_lastframe = host_framecount;

-			// if this is the second frame, grab the real td_starttime

-			// so the bogus time on the first frame doesn't count

-				if (host_framecount == cls.td_startframe + 1)

-					cls.td_starttime = realtime;

-			}

-			else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0])

-			{

-					return 0;		// don't need another message yet

-			}

-		}

-		

-	// get the next message

-		fread (&net_message.cursize, 4, 1, cls.demofile);

-		VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);

-		for (i=0 ; i<3 ; i++)

-		{

-			r = fread (&f, 4, 1, cls.demofile);

-			cl.mviewangles[0][i] = LittleFloat (f);

-		}

-		

-		net_message.cursize = LittleLong (net_message.cursize);

-		if (net_message.cursize > MAX_MSGLEN)

-			Sys_Error ("Demo message > MAX_MSGLEN");

-		r = fread (net_message.data, net_message.cursize, 1, cls.demofile);

-		if (r != 1)

-		{

-			CL_StopPlayback ();

-			return 0;

-		}

-	

-		return 1;

-	}

-

-	while (1)

-	{

-		r = NET_GetMessage (cls.netcon);

-		

-		if (r != 1 && r != 2)

-			return r;

-	

-	// discard nop keepalive message

-		if (net_message.cursize == 1 && net_message.data[0] == svc_nop)

-			Con_Printf ("<-- server to client keepalive\n");

-		else

-			break;

-	}

-

-	if (cls.demorecording)

-		CL_WriteDemoMessage ();

-	

-	return r;

-}

-

-

-/*

-====================

-CL_Stop_f

-

-stop recording a demo

-====================

-*/

-void CL_Stop_f (void)

-{

-	if (cmd_source != src_command)

-		return;

-

-	if (!cls.demorecording)

-	{

-		Con_Printf ("Not recording a demo.\n");

-		return;

-	}

-

-// write a disconnect message to the demo file

-	SZ_Clear (&net_message);

-	MSG_WriteByte (&net_message, svc_disconnect);

-	CL_WriteDemoMessage ();

-

-// finish up

-	fclose (cls.demofile);

-	cls.demofile = NULL;

-	cls.demorecording = false;

-	Con_Printf ("Completed demo\n");

-}

-

-/*

-====================

-CL_Record_f

-

-record <demoname> <map> [cd track]

-====================

-*/

-void CL_Record_f (void)

-{

-	int		c;

-	char	name[MAX_OSPATH];

-	int		track;

-

-	if (cmd_source != src_command)

-		return;

-

-	c = Cmd_Argc();

-	if (c != 2 && c != 3 && c != 4)

-	{

-		Con_Printf ("record <demoname> [<map> [cd track]]\n");

-		return;

-	}

-

-	if (strstr(Cmd_Argv(1), ".."))

-	{

-		Con_Printf ("Relative pathnames are not allowed.\n");

-		return;

-	}

-

-	if (c == 2 && cls.state == ca_connected)

-	{

-		Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n");

-		return;

-	}

-

-// write the forced cd track number, or -1

-	if (c == 4)

-	{

-		track = atoi(Cmd_Argv(3));

-		Con_Printf ("Forcing CD track to %i\n", cls.forcetrack);

-	}

-	else

-		track = -1;	

-

-	sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));

-	

-//

-// start the map up

-//

-	if (c > 2)

-		Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);

-	

-//

-// open the demo file

-//

-	COM_DefaultExtension (name, ".dem");

-

-	Con_Printf ("recording to %s.\n", name);

-	cls.demofile = fopen (name, "wb");

-	if (!cls.demofile)

-	{

-		Con_Printf ("ERROR: couldn't open.\n");

-		return;

-	}

-

-	cls.forcetrack = track;

-	fprintf (cls.demofile, "%i\n", cls.forcetrack);

-	

-	cls.demorecording = true;

-}

-

-

-/*

-====================

-CL_PlayDemo_f

-

-play [demoname]

-====================

-*/

-void CL_PlayDemo_f (void)

-{

-	char	name[256];

-	int c;

-	qboolean neg = false;

-

-	if (cmd_source != src_command)

-		return;

-

-	if (Cmd_Argc() != 2)

-	{

-		Con_Printf ("play <demoname> : plays a demo\n");

-		return;

-	}

-

-//

-// disconnect from server

-//

-	CL_Disconnect ();

-	

-//

-// open the demo file

-//

-	strcpy (name, Cmd_Argv(1));

-	COM_DefaultExtension (name, ".dem");

-

-	Con_Printf ("Playing demo from %s.\n", name);

-	COM_FOpenFile (name, &cls.demofile);

-	if (!cls.demofile)

-	{

-		Con_Printf ("ERROR: couldn't open.\n");

-		cls.demonum = -1;		// stop demo loop

-		return;

-	}

-

-	cls.demoplayback = true;

-	cls.state = ca_connected;

-	cls.forcetrack = 0;

-

-	while ((c = getc(cls.demofile)) != '\n')

-		if (c == '-')

-			neg = true;

-		else

-			cls.forcetrack = cls.forcetrack * 10 + (c - '0');

-

-	if (neg)

-		cls.forcetrack = -cls.forcetrack;

-// ZOID, fscanf is evil

-//	fscanf (cls.demofile, "%i\n", &cls.forcetrack);

-}

-

-/*

-====================

-CL_FinishTimeDemo

-

-====================

-*/

-void CL_FinishTimeDemo (void)

-{

-	int		frames;

-	float	time;

-	

-	cls.timedemo = false;

-	

-// the first frame didn't count

-	frames = (host_framecount - cls.td_startframe) - 1;

-	time = realtime - cls.td_starttime;

-	if (!time)

-		time = 1;

-	Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time);

-}

-

-/*

-====================

-CL_TimeDemo_f

-

-timedemo [demoname]

-====================

-*/

-void CL_TimeDemo_f (void)

-{

-	if (cmd_source != src_command)

-		return;

-

-	if (Cmd_Argc() != 2)

-	{

-		Con_Printf ("timedemo <demoname> : gets demo speeds\n");

-		return;

-	}

-

-	CL_PlayDemo_f ();

-	

-// cls.td_starttime will be grabbed at the second frame of the demo, so

-// all the loading time doesn't get counted

-	

-	cls.timedemo = true;

-	cls.td_startframe = host_framecount;

-	cls.td_lastframe = -1;		// get a new message this frame

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+void CL_FinishTimeDemo (void);
+
+/*
+==============================================================================
+
+DEMO CODE
+
+When a demo is playing back, all NET_SendMessages are skipped, and
+NET_GetMessages are read from the demo file.
+
+Whenever cl.time gets past the last received message, another message is
+read from the demo file.
+==============================================================================
+*/
+
+/*
+==============
+CL_StopPlayback
+
+Called when a demo file runs out, or the user starts a game
+==============
+*/
+void CL_StopPlayback (void)
+{
+	if (!cls.demoplayback)
+		return;
+
+	fclose (cls.demofile);
+	cls.demoplayback = false;
+	cls.demofile = NULL;
+	cls.state = ca_disconnected;
+
+	if (cls.timedemo)
+		CL_FinishTimeDemo ();
+}
+
+/*
+====================
+CL_WriteDemoMessage
+
+Dumps the current net message, prefixed by the length and view angles
+====================
+*/
+void CL_WriteDemoMessage (void)
+{
+	int		len;
+	int		i;
+	float	f;
+
+	len = LittleLong (net_message.cursize);
+	fwrite (&len, 4, 1, cls.demofile);
+	for (i=0 ; i<3 ; i++)
+	{
+		f = LittleFloat (cl.viewangles[i]);
+		fwrite (&f, 4, 1, cls.demofile);
+	}
+	fwrite (net_message.data, net_message.cursize, 1, cls.demofile);
+	fflush (cls.demofile);
+}
+
+/*
+====================
+CL_GetMessage
+
+Handles recording and playback of demos, on top of NET_ code
+====================
+*/
+int CL_GetMessage (void)
+{
+	int		r, i;
+	float	f;
+	
+	if	(cls.demoplayback)
+	{
+	// decide if it is time to grab the next message		
+		if (cls.signon == SIGNONS)	// allways grab until fully connected
+		{
+			if (cls.timedemo)
+			{
+				if (host_framecount == cls.td_lastframe)
+					return 0;		// allready read this frame's message
+				cls.td_lastframe = host_framecount;
+			// if this is the second frame, grab the real td_starttime
+			// so the bogus time on the first frame doesn't count
+				if (host_framecount == cls.td_startframe + 1)
+					cls.td_starttime = realtime;
+			}
+			else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0])
+			{
+					return 0;		// don't need another message yet
+			}
+		}
+		
+	// get the next message
+		fread (&net_message.cursize, 4, 1, cls.demofile);
+		VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);
+		for (i=0 ; i<3 ; i++)
+		{
+			r = fread (&f, 4, 1, cls.demofile);
+			cl.mviewangles[0][i] = LittleFloat (f);
+		}
+		
+		net_message.cursize = LittleLong (net_message.cursize);
+		if (net_message.cursize > MAX_MSGLEN)
+			Sys_Error ("Demo message > MAX_MSGLEN");
+		r = fread (net_message.data, net_message.cursize, 1, cls.demofile);
+		if (r != 1)
+		{
+			CL_StopPlayback ();
+			return 0;
+		}
+	
+		return 1;
+	}
+
+	while (1)
+	{
+		r = NET_GetMessage (cls.netcon);
+		
+		if (r != 1 && r != 2)
+			return r;
+	
+	// discard nop keepalive message
+		if (net_message.cursize == 1 && net_message.data[0] == svc_nop)
+			Con_Printf ("<-- server to client keepalive\n");
+		else
+			break;
+	}
+
+	if (cls.demorecording)
+		CL_WriteDemoMessage ();
+	
+	return r;
+}
+
+
+/*
+====================
+CL_Stop_f
+
+stop recording a demo
+====================
+*/
+void CL_Stop_f (void)
+{
+	if (cmd_source != src_command)
+		return;
+
+	if (!cls.demorecording)
+	{
+		Con_Printf ("Not recording a demo.\n");
+		return;
+	}
+
+// write a disconnect message to the demo file
+	SZ_Clear (&net_message);
+	MSG_WriteByte (&net_message, svc_disconnect);
+	CL_WriteDemoMessage ();
+
+// finish up
+	fclose (cls.demofile);
+	cls.demofile = NULL;
+	cls.demorecording = false;
+	Con_Printf ("Completed demo\n");
+}
+
+/*
+====================
+CL_Record_f
+
+record <demoname> <map> [cd track]
+====================
+*/
+void CL_Record_f (void)
+{
+	int		c;
+	char	name[MAX_OSPATH];
+	int		track;
+
+	if (cmd_source != src_command)
+		return;
+
+	c = Cmd_Argc();
+	if (c != 2 && c != 3 && c != 4)
+	{
+		Con_Printf ("record <demoname> [<map> [cd track]]\n");
+		return;
+	}
+
+	if (strstr(Cmd_Argv(1), ".."))
+	{
+		Con_Printf ("Relative pathnames are not allowed.\n");
+		return;
+	}
+
+	if (c == 2 && cls.state == ca_connected)
+	{
+		Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
+		return;
+	}
+
+// write the forced cd track number, or -1
+	if (c == 4)
+	{
+		track = atoi(Cmd_Argv(3));
+		Con_Printf ("Forcing CD track to %i\n", cls.forcetrack);
+	}
+	else
+		track = -1;	
+
+	sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
+	
+//
+// start the map up
+//
+	if (c > 2)
+		Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
+	
+//
+// open the demo file
+//
+	COM_DefaultExtension (name, ".dem");
+
+	Con_Printf ("recording to %s.\n", name);
+	cls.demofile = fopen (name, "wb");
+	if (!cls.demofile)
+	{
+		Con_Printf ("ERROR: couldn't open.\n");
+		return;
+	}
+
+	cls.forcetrack = track;
+	fprintf (cls.demofile, "%i\n", cls.forcetrack);
+	
+	cls.demorecording = true;
+}
+
+
+/*
+====================
+CL_PlayDemo_f
+
+play [demoname]
+====================
+*/
+void CL_PlayDemo_f (void)
+{
+	char	name[256];
+	int c;
+	qboolean neg = false;
+
+	if (cmd_source != src_command)
+		return;
+
+	if (Cmd_Argc() != 2)
+	{
+		Con_Printf ("play <demoname> : plays a demo\n");
+		return;
+	}
+
+//
+// disconnect from server
+//
+	CL_Disconnect ();
+	
+//
+// open the demo file
+//
+	strcpy (name, Cmd_Argv(1));
+	COM_DefaultExtension (name, ".dem");
+
+	Con_Printf ("Playing demo from %s.\n", name);
+	COM_FOpenFile (name, &cls.demofile);
+	if (!cls.demofile)
+	{
+		Con_Printf ("ERROR: couldn't open.\n");
+		cls.demonum = -1;		// stop demo loop
+		return;
+	}
+
+	cls.demoplayback = true;
+	cls.state = ca_connected;
+	cls.forcetrack = 0;
+
+	while ((c = getc(cls.demofile)) != '\n')
+		if (c == '-')
+			neg = true;
+		else
+			cls.forcetrack = cls.forcetrack * 10 + (c - '0');
+
+	if (neg)
+		cls.forcetrack = -cls.forcetrack;
+// ZOID, fscanf is evil
+//	fscanf (cls.demofile, "%i\n", &cls.forcetrack);
+}
+
+// The timedemo numbers are very important to testing, so log them even if normal console printing is disabled.
+
+#define LOGANDPRINT(ARGS) Con_Printf ARGS ; PMPLOG(ARGS)
+
+/*
+====================
+CL_FinishTimeDemo
+
+====================
+*/
+void CL_FinishTimeDemo (void)
+{
+	int		frames;
+	float	time;
+	
+	cls.timedemo = false;
+	
+// the first frame didn't count
+	frames = (host_framecount - cls.td_startframe) - 1;
+	time = realtime - cls.td_starttime;
+	if (!time)
+		time = 1;
+	LOGANDPRINT(("%i frames %5.3f seconds %5.3f fps\n", frames, time, frames/time));
+	if (frames > 0)
+	{
+		LOGANDPRINT(("Fastest: %5.1f ms on frame %d\n", fastestFrame.time * 1000.0, fastestFrame.frame));
+		LOGANDPRINT(("Average: %5.1f ms\n", (time / frames) * 1000.0));
+		LOGANDPRINT(("Slowest: %5.1f ms on frame %d\n", slowestFrame.time * 1000.0, slowestFrame.frame));
+	}
+}
+
+/*
+====================
+CL_TimeDemo_f
+
+timedemo [demoname]
+====================
+*/
+void CL_TimeDemo_f (void)
+{
+	if (cmd_source != src_command)
+		return;
+
+	if (Cmd_Argc() != 2)
+	{
+		Con_Printf ("timedemo <demoname> : gets demo speeds\n");
+		return;
+	}
+
+	CL_PlayDemo_f ();
+	
+// cls.td_starttime will be grabbed at the second frame of the demo, so
+// all the loading time doesn't get counted
+	
+	cls.timedemo = true;
+	cls.td_startframe = host_framecount;
+	cls.td_lastframe = -1;		// get a new message this frame
+	
+	InitFrameTimes();
+}
+
diff --git a/quake/src/WinQuake/cl_input.c b/quake/src/WinQuake/cl_input.cpp
old mode 100644
new mode 100755
similarity index 93%
rename from quake/src/WinQuake/cl_input.c
rename to quake/src/WinQuake/cl_input.cpp
index 41a7932..c58392e
--- a/quake/src/WinQuake/cl_input.c
+++ b/quake/src/WinQuake/cl_input.cpp
@@ -1,448 +1,459 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// cl.input.c  -- builds an intended movement command to send to the server

-

-// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All

-// rights reserved.

-

-#include "quakedef.h"

-

-/*

-===============================================================================

-

-KEY BUTTONS

-

-Continuous button event tracking is complicated by the fact that two different

-input sources (say, mouse button 1 and the control key) can both press the

-same button, but the button should only be released when both of the

-pressing key have been released.

-

-When a key event issues a button command (+forward, +attack, etc), it appends

-its key number as a parameter to the command so it can be matched up with

-the release.

-

-state bit 0 is the current state of the key

-state bit 1 is edge triggered on the up to down transition

-state bit 2 is edge triggered on the down to up transition

-

-===============================================================================

-*/

-

-

-kbutton_t	in_mlook, in_klook;

-kbutton_t	in_left, in_right, in_forward, in_back;

-kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;

-kbutton_t	in_strafe, in_speed, in_use, in_jump, in_attack;

-kbutton_t	in_up, in_down;

-

-int			in_impulse;

-

-

-void KeyDown (kbutton_t *b)

-{

-	int		k;

-	char	*c;

-

-	c = Cmd_Argv(1);

-	if (c[0])

-		k = atoi(c);

-	else

-		k = -1;		// typed manually at the console for continuous down

-

-	if (k == b->down[0] || k == b->down[1])

-		return;		// repeating key

-	

-	if (!b->down[0])

-		b->down[0] = k;

-	else if (!b->down[1])

-		b->down[1] = k;

-	else

-	{

-		Con_Printf ("Three keys down for a button!\n");

-		return;

-	}

-	

-	if (b->state & 1)

-		return;		// still down

-	b->state |= 1 + 2;	// down + impulse down

-}

-

-void KeyUp (kbutton_t *b)

-{

-	int		k;

-	char	*c;

-	

-	c = Cmd_Argv(1);

-	if (c[0])

-		k = atoi(c);

-	else

-	{ // typed manually at the console, assume for unsticking, so clear all

-		b->down[0] = b->down[1] = 0;

-		b->state = 4;	// impulse up

-		return;

-	}

-

-	if (b->down[0] == k)

-		b->down[0] = 0;

-	else if (b->down[1] == k)

-		b->down[1] = 0;

-	else

-		return;		// key up without coresponding down (menu pass through)

-	if (b->down[0] || b->down[1])

-		return;		// some other key is still holding it down

-

-	if (!(b->state & 1))

-		return;		// still up (this should not happen)

-	b->state &= ~1;		// now up

-	b->state |= 4; 		// impulse up

-}

-

-void IN_KLookDown (void) {KeyDown(&in_klook);}

-void IN_KLookUp (void) {KeyUp(&in_klook);}

-void IN_MLookDown (void) {KeyDown(&in_mlook);}

-void IN_MLookUp (void) {

-KeyUp(&in_mlook);

-if ( !(in_mlook.state&1) &&  lookspring.value)

-	V_StartPitchDrift();

-}

-void IN_UpDown(void) {KeyDown(&in_up);}

-void IN_UpUp(void) {KeyUp(&in_up);}

-void IN_DownDown(void) {KeyDown(&in_down);}

-void IN_DownUp(void) {KeyUp(&in_down);}

-void IN_LeftDown(void) {KeyDown(&in_left);}

-void IN_LeftUp(void) {KeyUp(&in_left);}

-void IN_RightDown(void) {KeyDown(&in_right);}

-void IN_RightUp(void) {KeyUp(&in_right);}

-void IN_ForwardDown(void) {KeyDown(&in_forward);}

-void IN_ForwardUp(void) {KeyUp(&in_forward);}

-void IN_BackDown(void) {KeyDown(&in_back);}

-void IN_BackUp(void) {KeyUp(&in_back);}

-void IN_LookupDown(void) {KeyDown(&in_lookup);}

-void IN_LookupUp(void) {KeyUp(&in_lookup);}

-void IN_LookdownDown(void) {KeyDown(&in_lookdown);}

-void IN_LookdownUp(void) {KeyUp(&in_lookdown);}

-void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}

-void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}

-void IN_MoverightDown(void) {KeyDown(&in_moveright);}

-void IN_MoverightUp(void) {KeyUp(&in_moveright);}

-

-void IN_SpeedDown(void) {KeyDown(&in_speed);}

-void IN_SpeedUp(void) {KeyUp(&in_speed);}

-void IN_StrafeDown(void) {KeyDown(&in_strafe);}

-void IN_StrafeUp(void) {KeyUp(&in_strafe);}

-

-void IN_AttackDown(void) {KeyDown(&in_attack);}

-void IN_AttackUp(void) {KeyUp(&in_attack);}

-

-void IN_UseDown (void) {KeyDown(&in_use);}

-void IN_UseUp (void) {KeyUp(&in_use);}

-void IN_JumpDown (void) {KeyDown(&in_jump);}

-void IN_JumpUp (void) {KeyUp(&in_jump);}

-

-void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));}

-

-/*

-===============

-CL_KeyState

-

-Returns 0.25 if a key was pressed and released during the frame,

-0.5 if it was pressed and held

-0 if held then released, and

-1.0 if held for the entire time

-===============

-*/

-float CL_KeyState (kbutton_t *key)

-{

-	float		val;

-	qboolean	impulsedown, impulseup, down;

-	

-	impulsedown = key->state & 2;

-	impulseup = key->state & 4;

-	down = key->state & 1;

-	val = 0;

-	

-	if (impulsedown && !impulseup)

-		if (down)

-			val = 0.5;	// pressed and held this frame

-		else

-			val = 0;	//	I_Error ();

-	if (impulseup && !impulsedown)

-		if (down)

-			val = 0;	//	I_Error ();

-		else

-			val = 0;	// released this frame

-	if (!impulsedown && !impulseup)

-		if (down)

-			val = 1.0;	// held the entire frame

-		else

-			val = 0;	// up the entire frame

-	if (impulsedown && impulseup)

-		if (down)

-			val = 0.75;	// released and re-pressed this frame

-		else

-			val = 0.25;	// pressed and released this frame

-

-	key->state &= 1;		// clear impulses

-	

-	return val;

-}

-

-

-

-

-//==========================================================================

-

-cvar_t	cl_upspeed = {"cl_upspeed","200"};

-cvar_t	cl_forwardspeed = {"cl_forwardspeed","200", true};

-cvar_t	cl_backspeed = {"cl_backspeed","200", true};

-cvar_t	cl_sidespeed = {"cl_sidespeed","350"};

-

-cvar_t	cl_movespeedkey = {"cl_movespeedkey","2.0"};

-

-cvar_t	cl_yawspeed = {"cl_yawspeed","140"};

-cvar_t	cl_pitchspeed = {"cl_pitchspeed","150"};

-

-cvar_t	cl_anglespeedkey = {"cl_anglespeedkey","1.5"};

-

-

-/*

-================

-CL_AdjustAngles

-

-Moves the local angle positions

-================

-*/

-void CL_AdjustAngles (void)

-{

-	float	speed;

-	float	up, down;

-	

-	if (in_speed.state & 1)

-		speed = host_frametime * cl_anglespeedkey.value;

-	else

-		speed = host_frametime;

-

-	if (!(in_strafe.state & 1))

-	{

-		cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);

-		cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);

-		cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);

-	}

-	if (in_klook.state & 1)

-	{

-		V_StopPitchDrift ();

-		cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);

-		cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);

-	}

-	

-	up = CL_KeyState (&in_lookup);

-	down = CL_KeyState(&in_lookdown);

-	

-	cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;

-	cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;

-

-	if (up || down)

-		V_StopPitchDrift ();

-		

-	if (cl.viewangles[PITCH] > 80)

-		cl.viewangles[PITCH] = 80;

-	if (cl.viewangles[PITCH] < -70)

-		cl.viewangles[PITCH] = -70;

-

-	if (cl.viewangles[ROLL] > 50)

-		cl.viewangles[ROLL] = 50;

-	if (cl.viewangles[ROLL] < -50)

-		cl.viewangles[ROLL] = -50;

-		

-}

-

-/*

-================

-CL_BaseMove

-

-Send the intended movement message to the server

-================

-*/

-void CL_BaseMove (usercmd_t *cmd)

-{	

-	if (cls.signon != SIGNONS)

-		return;

-			

-	CL_AdjustAngles ();

-	

-	Q_memset (cmd, 0, sizeof(*cmd));

-	

-	if (in_strafe.state & 1)

-	{

-		cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);

-		cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);

-	}

-

-	cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);

-	cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);

-

-	cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);

-	cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);

-

-	if (! (in_klook.state & 1) )

-	{	

-		cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);

-		cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);

-	}	

-

-//

-// adjust for speed key

-//

-	if (in_speed.state & 1)

-	{

-		cmd->forwardmove *= cl_movespeedkey.value;

-		cmd->sidemove *= cl_movespeedkey.value;

-		cmd->upmove *= cl_movespeedkey.value;

-	}

-

-#ifdef QUAKE2

-	cmd->lightlevel = cl.light_level;

-#endif

-}

-

-

-

-/*

-==============

-CL_SendMove

-==============

-*/

-void CL_SendMove (usercmd_t *cmd)

-{

-	int		i;

-	int		bits;

-	sizebuf_t	buf;

-	byte	data[128];

-	

-	buf.maxsize = 128;

-	buf.cursize = 0;

-	buf.data = data;

-	

-	cl.cmd = *cmd;

-

-//

-// send the movement message

-//

-    MSG_WriteByte (&buf, clc_move);

-

-	MSG_WriteFloat (&buf, cl.mtime[0]);	// so server can get ping times

-

-	for (i=0 ; i<3 ; i++)

-		MSG_WriteAngle (&buf, cl.viewangles[i]);

-	

-    MSG_WriteShort (&buf, cmd->forwardmove);

-    MSG_WriteShort (&buf, cmd->sidemove);

-    MSG_WriteShort (&buf, cmd->upmove);

-

-//

-// send button bits

-//

-	bits = 0;

-	

-	if ( in_attack.state & 3 )

-		bits |= 1;

-	in_attack.state &= ~2;

-	

-	if (in_jump.state & 3)

-		bits |= 2;

-	in_jump.state &= ~2;

-	

-    MSG_WriteByte (&buf, bits);

-

-    MSG_WriteByte (&buf, in_impulse);

-	in_impulse = 0;

-

-#ifdef QUAKE2

-//

-// light level

-//

-	MSG_WriteByte (&buf, cmd->lightlevel);

-#endif

-

-//

-// deliver the message

-//

-	if (cls.demoplayback)

-		return;

-

-//

-// allways dump the first two message, because it may contain leftover inputs

-// from the last level

-//

-	if (++cl.movemessages <= 2)

-		return;

-	

-	if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)

-	{

-		Con_Printf ("CL_SendMove: lost server connection\n");

-		CL_Disconnect ();

-	}

-}

-

-/*

-============

-CL_InitInput

-============

-*/

-void CL_InitInput (void)

-{

-	Cmd_AddCommand ("+moveup",IN_UpDown);

-	Cmd_AddCommand ("-moveup",IN_UpUp);

-	Cmd_AddCommand ("+movedown",IN_DownDown);

-	Cmd_AddCommand ("-movedown",IN_DownUp);

-	Cmd_AddCommand ("+left",IN_LeftDown);

-	Cmd_AddCommand ("-left",IN_LeftUp);

-	Cmd_AddCommand ("+right",IN_RightDown);

-	Cmd_AddCommand ("-right",IN_RightUp);

-	Cmd_AddCommand ("+forward",IN_ForwardDown);

-	Cmd_AddCommand ("-forward",IN_ForwardUp);

-	Cmd_AddCommand ("+back",IN_BackDown);

-	Cmd_AddCommand ("-back",IN_BackUp);

-	Cmd_AddCommand ("+lookup", IN_LookupDown);

-	Cmd_AddCommand ("-lookup", IN_LookupUp);

-	Cmd_AddCommand ("+lookdown", IN_LookdownDown);

-	Cmd_AddCommand ("-lookdown", IN_LookdownUp);

-	Cmd_AddCommand ("+strafe", IN_StrafeDown);

-	Cmd_AddCommand ("-strafe", IN_StrafeUp);

-	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);

-	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);

-	Cmd_AddCommand ("+moveright", IN_MoverightDown);

-	Cmd_AddCommand ("-moveright", IN_MoverightUp);

-	Cmd_AddCommand ("+speed", IN_SpeedDown);

-	Cmd_AddCommand ("-speed", IN_SpeedUp);

-	Cmd_AddCommand ("+attack", IN_AttackDown);

-	Cmd_AddCommand ("-attack", IN_AttackUp);

-	Cmd_AddCommand ("+use", IN_UseDown);

-	Cmd_AddCommand ("-use", IN_UseUp);

-	Cmd_AddCommand ("+jump", IN_JumpDown);

-	Cmd_AddCommand ("-jump", IN_JumpUp);

-	Cmd_AddCommand ("impulse", IN_Impulse);

-	Cmd_AddCommand ("+klook", IN_KLookDown);

-	Cmd_AddCommand ("-klook", IN_KLookUp);

-	Cmd_AddCommand ("+mlook", IN_MLookDown);

-	Cmd_AddCommand ("-mlook", IN_MLookUp);

-

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// cl.input.c  -- builds an intended movement command to send to the server
+
+// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
+// rights reserved.
+
+#include "quakedef.h"
+
+/*
+===============================================================================
+
+KEY BUTTONS
+
+Continuous button event tracking is complicated by the fact that two different
+input sources (say, mouse button 1 and the control key) can both press the
+same button, but the button should only be released when both of the
+pressing key have been released.
+
+When a key event issues a button command (+forward, +attack, etc), it appends
+its key number as a parameter to the command so it can be matched up with
+the release.
+
+state bit 0 is the current state of the key
+state bit 1 is edge triggered on the up to down transition
+state bit 2 is edge triggered on the down to up transition
+
+===============================================================================
+*/
+
+
+kbutton_t	in_mlook, in_klook;
+kbutton_t	in_left, in_right, in_forward, in_back;
+kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;
+kbutton_t	in_strafe, in_speed, in_use, in_jump, in_attack;
+kbutton_t	in_up, in_down;
+
+int			in_impulse;
+
+
+void KeyDown (kbutton_t *b)
+{
+	int		k;
+	const char	*c;
+
+	c = Cmd_Argv(1);
+	if (c[0])
+		k = atoi(c);
+	else
+		k = -1;		// typed manually at the console for continuous down
+
+	if (k == b->down[0] || k == b->down[1])
+		return;		// repeating key
+	
+	if (!b->down[0])
+		b->down[0] = k;
+	else if (!b->down[1])
+		b->down[1] = k;
+	else
+	{
+		Con_Printf ("Three keys down for a button!\n");
+		return;
+	}
+	
+	if (b->state & 1)
+		return;		// still down
+	b->state |= 1 + 2;	// down + impulse down
+}
+
+void KeyUp (kbutton_t *b)
+{
+	int		k;
+	const char	*c;
+	
+	c = Cmd_Argv(1);
+	if (c[0])
+		k = atoi(c);
+	else
+	{ // typed manually at the console, assume for unsticking, so clear all
+		b->down[0] = b->down[1] = 0;
+		b->state = 4;	// impulse up
+		return;
+	}
+
+	if (b->down[0] == k)
+		b->down[0] = 0;
+	else if (b->down[1] == k)
+		b->down[1] = 0;
+	else
+		return;		// key up without coresponding down (menu pass through)
+	if (b->down[0] || b->down[1])
+		return;		// some other key is still holding it down
+
+	if (!(b->state & 1))
+		return;		// still up (this should not happen)
+	b->state &= ~1;		// now up
+	b->state |= 4; 		// impulse up
+}
+
+void IN_KLookDown (void) {KeyDown(&in_klook);}
+void IN_KLookUp (void) {KeyUp(&in_klook);}
+void IN_MLookDown (void) {KeyDown(&in_mlook);}
+void IN_MLookUp (void) {
+KeyUp(&in_mlook);
+if ( !(in_mlook.state&1) &&  lookspring.value)
+	V_StartPitchDrift();
+}
+void IN_UpDown(void) {KeyDown(&in_up);}
+void IN_UpUp(void) {KeyUp(&in_up);}
+void IN_DownDown(void) {KeyDown(&in_down);}
+void IN_DownUp(void) {KeyUp(&in_down);}
+void IN_LeftDown(void) {KeyDown(&in_left);}
+void IN_LeftUp(void) {KeyUp(&in_left);}
+void IN_RightDown(void) {KeyDown(&in_right);}
+void IN_RightUp(void) {KeyUp(&in_right);}
+void IN_ForwardDown(void) {KeyDown(&in_forward);}
+void IN_ForwardUp(void) {KeyUp(&in_forward);}
+void IN_BackDown(void) {KeyDown(&in_back);}
+void IN_BackUp(void) {KeyUp(&in_back);}
+void IN_LookupDown(void) {KeyDown(&in_lookup);}
+void IN_LookupUp(void) {KeyUp(&in_lookup);}
+void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
+void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
+void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
+void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
+void IN_MoverightDown(void) {KeyDown(&in_moveright);}
+void IN_MoverightUp(void) {KeyUp(&in_moveright);}
+
+void IN_SpeedDown(void) {KeyDown(&in_speed);}
+void IN_SpeedUp(void) {KeyUp(&in_speed);}
+void IN_StrafeDown(void) {KeyDown(&in_strafe);}
+void IN_StrafeUp(void) {KeyUp(&in_strafe);}
+
+void IN_AttackDown(void) {KeyDown(&in_attack);}
+void IN_AttackUp(void) {KeyUp(&in_attack);}
+
+void IN_UseDown (void) {KeyDown(&in_use);}
+void IN_UseUp (void) {KeyUp(&in_use);}
+void IN_JumpDown (void) {KeyDown(&in_jump);}
+void IN_JumpUp (void) {KeyUp(&in_jump);}
+
+void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));}
+
+/*
+===============
+CL_KeyState
+
+Returns 0.25 if a key was pressed and released during the frame,
+0.5 if it was pressed and held
+0 if held then released, and
+1.0 if held for the entire time
+===============
+*/
+float CL_KeyState (kbutton_t *key)
+{
+	float		val;
+	qboolean	impulsedown, impulseup, down;
+	
+	impulsedown = key->state & 2;
+	impulseup = key->state & 4;
+	down = key->state & 1;
+	val = 0;
+	
+	if (impulsedown && !impulseup)
+	{
+		if (down)
+			val = 0.5;	// pressed and held this frame
+		else
+			val = 0;	//	I_Error ();
+	}
+	
+	if (impulseup && !impulsedown)
+	{
+		if (down)
+			val = 0;	//	I_Error ();
+		else
+			val = 0;	// released this frame
+	}
+	
+	if (!impulsedown && !impulseup)
+	{
+		if (down)
+			val = 1.0;	// held the entire frame
+		else
+			val = 0;	// up the entire frame
+	}
+	
+	if (impulsedown && impulseup)
+	{
+		if (down)
+			val = 0.75;	// released and re-pressed this frame
+		else
+			val = 0.25;	// pressed and released this frame
+	}
+
+	key->state &= 1;		// clear impulses
+	
+	return val;
+}
+
+
+
+
+//==========================================================================
+
+cvar_t	cl_upspeed = CVAR2("cl_upspeed","200");
+cvar_t	cl_forwardspeed = CVAR3("cl_forwardspeed","200", true);
+cvar_t	cl_backspeed = CVAR3("cl_backspeed","200", true);
+cvar_t	cl_sidespeed = CVAR2("cl_sidespeed","350");
+
+cvar_t	cl_movespeedkey = CVAR2("cl_movespeedkey","2.0");
+
+cvar_t	cl_yawspeed = CVAR2("cl_yawspeed","140");
+cvar_t	cl_pitchspeed = CVAR2("cl_pitchspeed","150");
+
+cvar_t	cl_anglespeedkey = CVAR2("cl_anglespeedkey","1.5");
+
+
+/*
+================
+CL_AdjustAngles
+
+Moves the local angle positions
+================
+*/
+void CL_AdjustAngles (void)
+{
+	float	speed;
+	float	up, down;
+	
+	if (in_speed.state & 1)
+		speed = host_frametime * cl_anglespeedkey.value;
+	else
+		speed = host_frametime;
+
+	if (!(in_strafe.state & 1))
+	{
+		cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
+		cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
+		cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
+	}
+	if (in_klook.state & 1)
+	{
+		V_StopPitchDrift ();
+		cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
+		cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
+	}
+	
+	up = CL_KeyState (&in_lookup);
+	down = CL_KeyState(&in_lookdown);
+	
+	cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
+	cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
+
+	if (up || down)
+		V_StopPitchDrift ();
+		
+	if (cl.viewangles[PITCH] > 80)
+		cl.viewangles[PITCH] = 80;
+	if (cl.viewangles[PITCH] < -70)
+		cl.viewangles[PITCH] = -70;
+
+	if (cl.viewangles[ROLL] > 50)
+		cl.viewangles[ROLL] = 50;
+	if (cl.viewangles[ROLL] < -50)
+		cl.viewangles[ROLL] = -50;
+		
+}
+
+/*
+================
+CL_BaseMove
+
+Send the intended movement message to the server
+================
+*/
+void CL_BaseMove (usercmd_t *cmd)
+{	
+	if (cls.signon != SIGNONS)
+		return;
+			
+	CL_AdjustAngles ();
+	
+	Q_memset (cmd, 0, sizeof(*cmd));
+	
+	if (in_strafe.state & 1)
+	{
+		cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
+		cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
+	}
+
+	cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
+	cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
+
+	cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
+	cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
+
+	if (! (in_klook.state & 1) )
+	{	
+		cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
+		cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
+	}	
+
+//
+// adjust for speed key
+//
+	if (in_speed.state & 1)
+	{
+		cmd->forwardmove *= cl_movespeedkey.value;
+		cmd->sidemove *= cl_movespeedkey.value;
+		cmd->upmove *= cl_movespeedkey.value;
+	}
+
+#ifdef QUAKE2
+	cmd->lightlevel = cl.light_level;
+#endif
+}
+
+
+
+/*
+==============
+CL_SendMove
+==============
+*/
+void CL_SendMove (usercmd_t *cmd)
+{
+	int		i;
+	int		bits;
+	sizebuf_t	buf;
+	byte	data[128];
+	
+	buf.maxsize = 128;
+	buf.cursize = 0;
+	buf.data = data;
+	
+	cl.cmd = *cmd;
+
+//
+// send the movement message
+//
+    MSG_WriteByte (&buf, clc_move);
+
+	MSG_WriteFloat (&buf, cl.mtime[0]);	// so server can get ping times
+
+	for (i=0 ; i<3 ; i++)
+		MSG_WriteAngle (&buf, cl.viewangles[i]);
+	
+    MSG_WriteShort (&buf, (short) cmd->forwardmove);
+    MSG_WriteShort (&buf, (short) cmd->sidemove);
+    MSG_WriteShort (&buf, (short) cmd->upmove);
+
+//
+// send button bits
+//
+	bits = 0;
+	
+	if ( in_attack.state & 3 )
+		bits |= 1;
+	in_attack.state &= ~2;
+	
+	if (in_jump.state & 3)
+		bits |= 2;
+	in_jump.state &= ~2;
+	
+    MSG_WriteByte (&buf, bits);
+
+    MSG_WriteByte (&buf, in_impulse);
+	in_impulse = 0;
+
+#ifdef QUAKE2
+//
+// light level
+//
+	MSG_WriteByte (&buf, cmd->lightlevel);
+#endif
+
+//
+// deliver the message
+//
+	if (cls.demoplayback)
+		return;
+
+//
+// allways dump the first two message, because it may contain leftover inputs
+// from the last level
+//
+	if (++cl.movemessages <= 2)
+		return;
+	
+	if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
+	{
+		Con_Printf ("CL_SendMove: lost server connection\n");
+		CL_Disconnect ();
+	}
+}
+
+/*
+============
+CL_InitInput
+============
+*/
+void CL_InitInput (void)
+{
+	Cmd_AddCommand ("+moveup",IN_UpDown);
+	Cmd_AddCommand ("-moveup",IN_UpUp);
+	Cmd_AddCommand ("+movedown",IN_DownDown);
+	Cmd_AddCommand ("-movedown",IN_DownUp);
+	Cmd_AddCommand ("+left",IN_LeftDown);
+	Cmd_AddCommand ("-left",IN_LeftUp);
+	Cmd_AddCommand ("+right",IN_RightDown);
+	Cmd_AddCommand ("-right",IN_RightUp);
+	Cmd_AddCommand ("+forward",IN_ForwardDown);
+	Cmd_AddCommand ("-forward",IN_ForwardUp);
+	Cmd_AddCommand ("+back",IN_BackDown);
+	Cmd_AddCommand ("-back",IN_BackUp);
+	Cmd_AddCommand ("+lookup", IN_LookupDown);
+	Cmd_AddCommand ("-lookup", IN_LookupUp);
+	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
+	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
+	Cmd_AddCommand ("+strafe", IN_StrafeDown);
+	Cmd_AddCommand ("-strafe", IN_StrafeUp);
+	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
+	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
+	Cmd_AddCommand ("+moveright", IN_MoverightDown);
+	Cmd_AddCommand ("-moveright", IN_MoverightUp);
+	Cmd_AddCommand ("+speed", IN_SpeedDown);
+	Cmd_AddCommand ("-speed", IN_SpeedUp);
+	Cmd_AddCommand ("+attack", IN_AttackDown);
+	Cmd_AddCommand ("-attack", IN_AttackUp);
+	Cmd_AddCommand ("+use", IN_UseDown);
+	Cmd_AddCommand ("-use", IN_UseUp);
+	Cmd_AddCommand ("+jump", IN_JumpDown);
+	Cmd_AddCommand ("-jump", IN_JumpUp);
+	Cmd_AddCommand ("impulse", IN_Impulse);
+	Cmd_AddCommand ("+klook", IN_KLookDown);
+	Cmd_AddCommand ("-klook", IN_KLookUp);
+	Cmd_AddCommand ("+mlook", IN_MLookDown);
+	Cmd_AddCommand ("-mlook", IN_MLookUp);
+
+}
+
diff --git a/quake/src/WinQuake/cl_main.c b/quake/src/WinQuake/cl_main.cpp
old mode 100644
new mode 100755
similarity index 95%
rename from quake/src/WinQuake/cl_main.c
rename to quake/src/WinQuake/cl_main.cpp
index 897b9a4..3fcfb22
--- a/quake/src/WinQuake/cl_main.c
+++ b/quake/src/WinQuake/cl_main.cpp
@@ -1,757 +1,757 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// cl_main.c  -- client main loop

-

-#include "quakedef.h"

-

-// we need to declare some mouse variables here, because the menu system

-// references them even when on a unix system.

-

-// these two are not intended to be set directly

-cvar_t	cl_name = {"_cl_name", "player", true};

-cvar_t	cl_color = {"_cl_color", "0", true};

-

-cvar_t	cl_shownet = {"cl_shownet","0"};	// can be 0, 1, or 2

-cvar_t	cl_nolerp = {"cl_nolerp","0"};

-

-cvar_t	lookspring = {"lookspring","0", true};

-cvar_t	lookstrafe = {"lookstrafe","0", true};

-cvar_t	sensitivity = {"sensitivity","3", true};

-

-cvar_t	m_pitch = {"m_pitch","0.022", true};

-cvar_t	m_yaw = {"m_yaw","0.022", true};

-cvar_t	m_forward = {"m_forward","1", true};

-cvar_t	m_side = {"m_side","0.8", true};

-

-

-client_static_t	cls;

-client_state_t	cl;

-// FIXME: put these on hunk?

-efrag_t			cl_efrags[MAX_EFRAGS];

-entity_t		cl_entities[MAX_EDICTS];

-entity_t		cl_static_entities[MAX_STATIC_ENTITIES];

-lightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];

-dlight_t		cl_dlights[MAX_DLIGHTS];

-

-int				cl_numvisedicts;

-entity_t		*cl_visedicts[MAX_VISEDICTS];

-

-/*

-=====================

-CL_ClearState

-

-=====================

-*/

-void CL_ClearState (void)

-{

-	int			i;

-

-	if (!sv.active)

-		Host_ClearMemory ();

-

-// wipe the entire cl structure

-	memset (&cl, 0, sizeof(cl));

-

-	SZ_Clear (&cls.message);

-

-// clear other arrays	

-	memset (cl_efrags, 0, sizeof(cl_efrags));

-	memset (cl_entities, 0, sizeof(cl_entities));

-	memset (cl_dlights, 0, sizeof(cl_dlights));

-	memset (cl_lightstyle, 0, sizeof(cl_lightstyle));

-	memset (cl_temp_entities, 0, sizeof(cl_temp_entities));

-	memset (cl_beams, 0, sizeof(cl_beams));

-

-//

-// allocate the efrags and chain together into a free list

-//

-	cl.free_efrags = cl_efrags;

-	for (i=0 ; i<MAX_EFRAGS-1 ; i++)

-		cl.free_efrags[i].entnext = &cl.free_efrags[i+1];

-	cl.free_efrags[i].entnext = NULL;

-}

-

-/*

-=====================

-CL_Disconnect

-

-Sends a disconnect message to the server

-This is also called on Host_Error, so it shouldn't cause any errors

-=====================

-*/

-void CL_Disconnect (void)

-{

-// stop sounds (especially looping!)

-	S_StopAllSounds (true);

-	

-// bring the console down and fade the colors back to normal

-//	SCR_BringDownConsole ();

-

-// if running a local server, shut it down

-	if (cls.demoplayback)

-		CL_StopPlayback ();

-	else if (cls.state == ca_connected)

-	{

-		if (cls.demorecording)

-			CL_Stop_f ();

-

-		Con_DPrintf ("Sending clc_disconnect\n");

-		SZ_Clear (&cls.message);

-		MSG_WriteByte (&cls.message, clc_disconnect);

-		NET_SendUnreliableMessage (cls.netcon, &cls.message);

-		SZ_Clear (&cls.message);

-		NET_Close (cls.netcon);

-

-		cls.state = ca_disconnected;

-		if (sv.active)

-			Host_ShutdownServer(false);

-	}

-

-	cls.demoplayback = cls.timedemo = false;

-	cls.signon = 0;

-}

-

-void CL_Disconnect_f (void)

-{

-	CL_Disconnect ();

-	if (sv.active)

-		Host_ShutdownServer (false);

-}

-

-

-

-

-/*

-=====================

-CL_EstablishConnection

-

-Host should be either "local" or a net address to be passed on

-=====================

-*/

-void CL_EstablishConnection (char *host)

-{

-	if (cls.state == ca_dedicated)

-		return;

-

-	if (cls.demoplayback)

-		return;

-

-	CL_Disconnect ();

-

-	cls.netcon = NET_Connect (host);

-	if (!cls.netcon)

-		Host_Error ("CL_Connect: connect failed\n");

-	Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);

-	

-	cls.demonum = -1;			// not in the demo loop now

-	cls.state = ca_connected;

-	cls.signon = 0;				// need all the signon messages before playing

-}

-

-/*

-=====================

-CL_SignonReply

-

-An svc_signonnum has been received, perform a client side setup

-=====================

-*/

-void CL_SignonReply (void)

-{

-	char 	str[8192];

-

-Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);

-

-	switch (cls.signon)

-	{

-	case 1:

-		MSG_WriteByte (&cls.message, clc_stringcmd);

-		MSG_WriteString (&cls.message, "prespawn");

-		break;

-		

-	case 2:		

-		MSG_WriteByte (&cls.message, clc_stringcmd);

-		MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));

-	

-		MSG_WriteByte (&cls.message, clc_stringcmd);

-		MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));

-	

-		MSG_WriteByte (&cls.message, clc_stringcmd);

-		sprintf (str, "spawn %s", cls.spawnparms);

-		MSG_WriteString (&cls.message, str);

-		break;

-		

-	case 3:	

-		MSG_WriteByte (&cls.message, clc_stringcmd);

-		MSG_WriteString (&cls.message, "begin");

-		Cache_Report ();		// print remaining memory

-		break;

-		

-	case 4:

-		SCR_EndLoadingPlaque ();		// allow normal screen updates

-		break;

-	}

-}

-

-/*

-=====================

-CL_NextDemo

-

-Called to play the next demo in the demo loop

-=====================

-*/

-void CL_NextDemo (void)

-{

-	char	str[1024];

-

-	if (cls.demonum == -1)

-		return;		// don't play demos

-

-	SCR_BeginLoadingPlaque ();

-

-	if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)

-	{

-		cls.demonum = 0;

-		if (!cls.demos[cls.demonum][0])

-		{

-			Con_Printf ("No demos listed with startdemos\n");

-			cls.demonum = -1;

-			return;

-		}

-	}

-

-	sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);

-	Cbuf_InsertText (str);

-	cls.demonum++;

-}

-

-/*

-==============

-CL_PrintEntities_f

-==============

-*/

-void CL_PrintEntities_f (void)

-{

-	entity_t	*ent;

-	int			i;

-	

-	for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)

-	{

-		Con_Printf ("%3i:",i);

-		if (!ent->model)

-		{

-			Con_Printf ("EMPTY\n");

-			continue;

-		}

-		Con_Printf ("%s:%2i  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"

-		,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);

-	}

-}

-

-

-/*

-===============

-SetPal

-

-Debugging tool, just flashes the screen

-===============

-*/

-void SetPal (int i)

-{

-#if 0

-	static int old;

-	byte	pal[768];

-	int		c;

-	

-	if (i == old)

-		return;

-	old = i;

-

-	if (i==0)

-		VID_SetPalette (host_basepal);

-	else if (i==1)

-	{

-		for (c=0 ; c<768 ; c+=3)

-		{

-			pal[c] = 0;

-			pal[c+1] = 255;

-			pal[c+2] = 0;

-		}

-		VID_SetPalette (pal);

-	}

-	else

-	{

-		for (c=0 ; c<768 ; c+=3)

-		{

-			pal[c] = 0;

-			pal[c+1] = 0;

-			pal[c+2] = 255;

-		}

-		VID_SetPalette (pal);

-	}

-#endif

-}

-

-/*

-===============

-CL_AllocDlight

-

-===============

-*/

-dlight_t *CL_AllocDlight (int key)

-{

-	int		i;

-	dlight_t	*dl;

-

-// first look for an exact key match

-	if (key)

-	{

-		dl = cl_dlights;

-		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)

-		{

-			if (dl->key == key)

-			{

-				memset (dl, 0, sizeof(*dl));

-				dl->key = key;

-				return dl;

-			}

-		}

-	}

-

-// then look for anything else

-	dl = cl_dlights;

-	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)

-	{

-		if (dl->die < cl.time)

-		{

-			memset (dl, 0, sizeof(*dl));

-			dl->key = key;

-			return dl;

-		}

-	}

-

-	dl = &cl_dlights[0];

-	memset (dl, 0, sizeof(*dl));

-	dl->key = key;

-	return dl;

-}

-

-

-/*

-===============

-CL_DecayLights

-

-===============

-*/

-void CL_DecayLights (void)

-{

-	int			i;

-	dlight_t	*dl;

-	float		time;

-	

-	time = cl.time - cl.oldtime;

-

-	dl = cl_dlights;

-	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)

-	{

-		if (dl->die < cl.time || !dl->radius)

-			continue;

-		

-		dl->radius -= time*dl->decay;

-		if (dl->radius < 0)

-			dl->radius = 0;

-	}

-}

-

-

-/*

-===============

-CL_LerpPoint

-

-Determines the fraction between the last two messages that the objects

-should be put at.

-===============

-*/

-float	CL_LerpPoint (void)

-{

-	float	f, frac;

-

-	f = cl.mtime[0] - cl.mtime[1];

-	

-	if (!f || cl_nolerp.value || cls.timedemo || sv.active)

-	{

-		cl.time = cl.mtime[0];

-		return 1;

-	}

-		

-	if (f > 0.1)

-	{	// dropped packet, or start of demo

-		cl.mtime[1] = cl.mtime[0] - 0.1;

-		f = 0.1;

-	}

-	frac = (cl.time - cl.mtime[1]) / f;

-//Con_Printf ("frac: %f\n",frac);

-	if (frac < 0)

-	{

-		if (frac < -0.01)

-		{

-SetPal(1);

-			cl.time = cl.mtime[1];

-//				Con_Printf ("low frac\n");

-		}

-		frac = 0;

-	}

-	else if (frac > 1)

-	{

-		if (frac > 1.01)

-		{

-SetPal(2);

-			cl.time = cl.mtime[0];

-//				Con_Printf ("high frac\n");

-		}

-		frac = 1;

-	}

-	else

-		SetPal(0);

-		

-	return frac;

-}

-

-

-/*

-===============

-CL_RelinkEntities

-===============

-*/

-void CL_RelinkEntities (void)

-{

-	entity_t	*ent;

-	int			i, j;

-	float		frac, f, d;

-	vec3_t		delta;

-	float		bobjrotate;

-	vec3_t		oldorg;

-	dlight_t	*dl;

-

-// determine partial update time	

-	frac = CL_LerpPoint ();

-

-	cl_numvisedicts = 0;

-

-//

-// interpolate player info

-//

-	for (i=0 ; i<3 ; i++)

-		cl.velocity[i] = cl.mvelocity[1][i] + 

-			frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);

-

-	if (cls.demoplayback)

-	{

-	// interpolate the angles	

-		for (j=0 ; j<3 ; j++)

-		{

-			d = cl.mviewangles[0][j] - cl.mviewangles[1][j];

-			if (d > 180)

-				d -= 360;

-			else if (d < -180)

-				d += 360;

-			cl.viewangles[j] = cl.mviewangles[1][j] + frac*d;

-		}

-	}

-	

-	bobjrotate = anglemod(100*cl.time);

-	

-// start on the entity after the world

-	for (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++)

-	{

-		if (!ent->model)

-		{	// empty slot

-			if (ent->forcelink)

-				R_RemoveEfrags (ent);	// just became empty

-			continue;

-		}

-

-// if the object wasn't included in the last packet, remove it

-		if (ent->msgtime != cl.mtime[0])

-		{

-			ent->model = NULL;

-			continue;

-		}

-

-		VectorCopy (ent->origin, oldorg);

-

-		if (ent->forcelink)

-		{	// the entity was not updated in the last message

-			// so move to the final spot

-			VectorCopy (ent->msg_origins[0], ent->origin);

-			VectorCopy (ent->msg_angles[0], ent->angles);

-		}

-		else

-		{	// if the delta is large, assume a teleport and don't lerp

-			f = frac;

-			for (j=0 ; j<3 ; j++)

-			{

-				delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];

-				if (delta[j] > 100 || delta[j] < -100)

-					f = 1;		// assume a teleportation, not a motion

-			}

-

-		// interpolate the origin and angles

-			for (j=0 ; j<3 ; j++)

-			{

-				ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];

-

-				d = ent->msg_angles[0][j] - ent->msg_angles[1][j];

-				if (d > 180)

-					d -= 360;

-				else if (d < -180)

-					d += 360;

-				ent->angles[j] = ent->msg_angles[1][j] + f*d;

-			}

-			

-		}

-

-// rotate binary objects locally

-		if (ent->model->flags & EF_ROTATE)

-			ent->angles[1] = bobjrotate;

-

-		if (ent->effects & EF_BRIGHTFIELD)

-			R_EntityParticles (ent);

-#ifdef QUAKE2

-		if (ent->effects & EF_DARKFIELD)

-			R_DarkFieldParticles (ent);

-#endif

-		if (ent->effects & EF_MUZZLEFLASH)

-		{

-			vec3_t		fv, rv, uv;

-

-			dl = CL_AllocDlight (i);

-			VectorCopy (ent->origin,  dl->origin);

-			dl->origin[2] += 16;

-			AngleVectors (ent->angles, fv, rv, uv);

-			 

-			VectorMA (dl->origin, 18, fv, dl->origin);

-			dl->radius = 200 + (rand()&31);

-			dl->minlight = 32;

-			dl->die = cl.time + 0.1;

-		}

-		if (ent->effects & EF_BRIGHTLIGHT)

-		{			

-			dl = CL_AllocDlight (i);

-			VectorCopy (ent->origin,  dl->origin);

-			dl->origin[2] += 16;

-			dl->radius = 400 + (rand()&31);

-			dl->die = cl.time + 0.001;

-		}

-		if (ent->effects & EF_DIMLIGHT)

-		{			

-			dl = CL_AllocDlight (i);

-			VectorCopy (ent->origin,  dl->origin);

-			dl->radius = 200 + (rand()&31);

-			dl->die = cl.time + 0.001;

-		}

-#ifdef QUAKE2

-		if (ent->effects & EF_DARKLIGHT)

-		{			

-			dl = CL_AllocDlight (i);

-			VectorCopy (ent->origin,  dl->origin);

-			dl->radius = 200.0 + (rand()&31);

-			dl->die = cl.time + 0.001;

-			dl->dark = true;

-		}

-		if (ent->effects & EF_LIGHT)

-		{			

-			dl = CL_AllocDlight (i);

-			VectorCopy (ent->origin,  dl->origin);

-			dl->radius = 200;

-			dl->die = cl.time + 0.001;

-		}

-#endif

-

-		if (ent->model->flags & EF_GIB)

-			R_RocketTrail (oldorg, ent->origin, 2);

-		else if (ent->model->flags & EF_ZOMGIB)

-			R_RocketTrail (oldorg, ent->origin, 4);

-		else if (ent->model->flags & EF_TRACER)

-			R_RocketTrail (oldorg, ent->origin, 3);

-		else if (ent->model->flags & EF_TRACER2)

-			R_RocketTrail (oldorg, ent->origin, 5);

-		else if (ent->model->flags & EF_ROCKET)

-		{

-			R_RocketTrail (oldorg, ent->origin, 0);

-			dl = CL_AllocDlight (i);

-			VectorCopy (ent->origin, dl->origin);

-			dl->radius = 200;

-			dl->die = cl.time + 0.01;

-		}

-		else if (ent->model->flags & EF_GRENADE)

-			R_RocketTrail (oldorg, ent->origin, 1);

-		else if (ent->model->flags & EF_TRACER3)

-			R_RocketTrail (oldorg, ent->origin, 6);

-

-		ent->forcelink = false;

-

-		if (i == cl.viewentity && !chase_active.value)

-			continue;

-

-#ifdef QUAKE2

-		if ( ent->effects & EF_NODRAW )

-			continue;

-#endif

-		if (cl_numvisedicts < MAX_VISEDICTS)

-		{

-			cl_visedicts[cl_numvisedicts] = ent;

-			cl_numvisedicts++;

-		}

-	}

-

-}

-

-

-/*

-===============

-CL_ReadFromServer

-

-Read all incoming data from the server

-===============

-*/

-int CL_ReadFromServer (void)

-{

-	int		ret;

-

-	cl.oldtime = cl.time;

-	cl.time += host_frametime;

-	

-	do

-	{

-		ret = CL_GetMessage ();

-		if (ret == -1)

-			Host_Error ("CL_ReadFromServer: lost server connection");

-		if (!ret)

-			break;

-		

-		cl.last_received_message = realtime;

-		CL_ParseServerMessage ();

-	} while (ret && cls.state == ca_connected);

-	

-	if (cl_shownet.value)

-		Con_Printf ("\n");

-

-	CL_RelinkEntities ();

-	CL_UpdateTEnts ();

-

-//

-// bring the links up to date

-//

-	return 0;

-}

-

-/*

-=================

-CL_SendCmd

-=================

-*/

-void CL_SendCmd (void)

-{

-	usercmd_t		cmd;

-

-	if (cls.state != ca_connected)

-		return;

-

-	if (cls.signon == SIGNONS)

-	{

-	// get basic movement from keyboard

-		CL_BaseMove (&cmd);

-	

-	// allow mice or other external controllers to add to the move

-		IN_Move (&cmd);

-	

-	// send the unreliable message

-		CL_SendMove (&cmd);

-	

-	}

-

-	if (cls.demoplayback)

-	{

-		SZ_Clear (&cls.message);

-		return;

-	}

-	

-// send the reliable message

-	if (!cls.message.cursize)

-		return;		// no message at all

-	

-	if (!NET_CanSendMessage (cls.netcon))

-	{

-		Con_DPrintf ("CL_WriteToServer: can't send\n");

-		return;

-	}

-

-	if (NET_SendMessage (cls.netcon, &cls.message) == -1)

-		Host_Error ("CL_WriteToServer: lost server connection");

-

-	SZ_Clear (&cls.message);

-}

-

-/*

-=================

-CL_Init

-=================

-*/

-void CL_Init (void)

-{	

-	SZ_Alloc (&cls.message, 1024);

-

-	CL_InitInput ();

-	CL_InitTEnts ();

-	

-//

-// register our commands

-//

-	Cvar_RegisterVariable (&cl_name);

-	Cvar_RegisterVariable (&cl_color);

-	Cvar_RegisterVariable (&cl_upspeed);

-	Cvar_RegisterVariable (&cl_forwardspeed);

-	Cvar_RegisterVariable (&cl_backspeed);

-	Cvar_RegisterVariable (&cl_sidespeed);

-	Cvar_RegisterVariable (&cl_movespeedkey);

-	Cvar_RegisterVariable (&cl_yawspeed);

-	Cvar_RegisterVariable (&cl_pitchspeed);

-	Cvar_RegisterVariable (&cl_anglespeedkey);

-	Cvar_RegisterVariable (&cl_shownet);

-	Cvar_RegisterVariable (&cl_nolerp);

-	Cvar_RegisterVariable (&lookspring);

-	Cvar_RegisterVariable (&lookstrafe);

-	Cvar_RegisterVariable (&sensitivity);

-

-	Cvar_RegisterVariable (&m_pitch);

-	Cvar_RegisterVariable (&m_yaw);

-	Cvar_RegisterVariable (&m_forward);

-	Cvar_RegisterVariable (&m_side);

-

-//	Cvar_RegisterVariable (&cl_autofire);

-	

-	Cmd_AddCommand ("entities", CL_PrintEntities_f);

-	Cmd_AddCommand ("disconnect", CL_Disconnect_f);

-	Cmd_AddCommand ("record", CL_Record_f);

-	Cmd_AddCommand ("stop", CL_Stop_f);

-	Cmd_AddCommand ("playdemo", CL_PlayDemo_f);

-	Cmd_AddCommand ("timedemo", CL_TimeDemo_f);

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// cl_main.c  -- client main loop
+
+#include "quakedef.h"
+
+// we need to declare some mouse variables here, because the menu system
+// references them even when on a unix system.
+
+// these two are not intended to be set directly
+cvar_t	cl_name = CVAR3("_cl_name", "player", true);
+cvar_t	cl_color = CVAR3("_cl_color", "0", true);
+
+cvar_t	cl_shownet = CVAR2("cl_shownet","0");	// can be 0, 1, or 2
+cvar_t	cl_nolerp = CVAR2("cl_nolerp","0");
+
+cvar_t	lookspring = CVAR3("lookspring","0", true);
+cvar_t	lookstrafe = CVAR3("lookstrafe","0", true);
+cvar_t	sensitivity = CVAR3("sensitivity","3", true);
+
+cvar_t	m_pitch = CVAR3("m_pitch","0.022", true);
+cvar_t	m_yaw = CVAR3("m_yaw","0.022", true);
+cvar_t	m_forward = CVAR3("m_forward","1", true);
+cvar_t	m_side = CVAR3("m_side","0.8", true);
+
+
+client_static_t	cls;
+client_state_t	cl;
+// FIXME: put these on hunk?
+efrag_t			cl_efrags[MAX_EFRAGS];
+entity_t		cl_entities[MAX_EDICTS];
+entity_t		cl_static_entities[MAX_STATIC_ENTITIES];
+lightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];
+dlight_t		cl_dlights[MAX_DLIGHTS];
+
+int				cl_numvisedicts;
+entity_t		*cl_visedicts[MAX_VISEDICTS];
+
+/*
+=====================
+CL_ClearState
+
+=====================
+*/
+void CL_ClearState (void)
+{
+	int			i;
+
+	if (!sv.active)
+		Host_ClearMemory ();
+
+// wipe the entire cl structure
+	memset (&cl, 0, sizeof(cl));
+
+	SZ_Clear (&cls.message);
+
+// clear other arrays	
+	memset (cl_efrags, 0, sizeof(cl_efrags));
+	memset (cl_entities, 0, sizeof(cl_entities));
+	memset (cl_dlights, 0, sizeof(cl_dlights));
+	memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
+	memset (cl_temp_entities, 0, sizeof(cl_temp_entities));
+	memset (cl_beams, 0, sizeof(cl_beams));
+
+//
+// allocate the efrags and chain together into a free list
+//
+	cl.free_efrags = cl_efrags;
+	for (i=0 ; i<MAX_EFRAGS-1 ; i++)
+		cl.free_efrags[i].entnext = &cl.free_efrags[i+1];
+	cl.free_efrags[i].entnext = NULL;
+}
+
+/*
+=====================
+CL_Disconnect
+
+Sends a disconnect message to the server
+This is also called on Host_Error, so it shouldn't cause any errors
+=====================
+*/
+void CL_Disconnect (void)
+{
+// stop sounds (especially looping!)
+	S_StopAllSounds (true);
+	
+// bring the console down and fade the colors back to normal
+//	SCR_BringDownConsole ();
+
+// if running a local server, shut it down
+	if (cls.demoplayback)
+		CL_StopPlayback ();
+	else if (cls.state == ca_connected)
+	{
+		if (cls.demorecording)
+			CL_Stop_f ();
+
+		Con_DPrintf ("Sending clc_disconnect\n");
+		SZ_Clear (&cls.message);
+		MSG_WriteByte (&cls.message, clc_disconnect);
+		NET_SendUnreliableMessage (cls.netcon, &cls.message);
+		SZ_Clear (&cls.message);
+		NET_Close (cls.netcon);
+
+		cls.state = ca_disconnected;
+		if (sv.active)
+			Host_ShutdownServer(false);
+	}
+
+	cls.demoplayback = cls.timedemo = false;
+	cls.signon = 0;
+}
+
+void CL_Disconnect_f (void)
+{
+	CL_Disconnect ();
+	if (sv.active)
+		Host_ShutdownServer (false);
+}
+
+
+
+
+/*
+=====================
+CL_EstablishConnection
+
+Host should be either "local" or a net address to be passed on
+=====================
+*/
+void CL_EstablishConnection (const char *host)
+{
+	if (cls.state == ca_dedicated)
+		return;
+
+	if (cls.demoplayback)
+		return;
+
+	CL_Disconnect ();
+
+	cls.netcon = NET_Connect (host);
+	if (!cls.netcon)
+		Host_Error ("CL_Connect: connect failed\n");
+	Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
+	
+	cls.demonum = -1;			// not in the demo loop now
+	cls.state = ca_connected;
+	cls.signon = 0;				// need all the signon messages before playing
+}
+
+/*
+=====================
+CL_SignonReply
+
+An svc_signonnum has been received, perform a client side setup
+=====================
+*/
+void CL_SignonReply (void)
+{
+	char 	str[8192];
+
+Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
+
+	switch (cls.signon)
+	{
+	case 1:
+		MSG_WriteByte (&cls.message, clc_stringcmd);
+		MSG_WriteString (&cls.message, "prespawn");
+		break;
+		
+	case 2:		
+		MSG_WriteByte (&cls.message, clc_stringcmd);
+		MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
+	
+		MSG_WriteByte (&cls.message, clc_stringcmd);
+		MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
+	
+		MSG_WriteByte (&cls.message, clc_stringcmd);
+		sprintf (str, "spawn %s", cls.spawnparms);
+		MSG_WriteString (&cls.message, str);
+		break;
+		
+	case 3:	
+		MSG_WriteByte (&cls.message, clc_stringcmd);
+		MSG_WriteString (&cls.message, "begin");
+		Cache_Report ();		// print remaining memory
+		break;
+		
+	case 4:
+		SCR_EndLoadingPlaque ();		// allow normal screen updates
+		break;
+	}
+}
+
+/*
+=====================
+CL_NextDemo
+
+Called to play the next demo in the demo loop
+=====================
+*/
+void CL_NextDemo (void)
+{
+	char	str[1024];
+
+	if (cls.demonum == -1)
+		return;		// don't play demos
+
+	SCR_BeginLoadingPlaque ();
+
+	if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
+	{
+		cls.demonum = 0;
+		if (!cls.demos[cls.demonum][0])
+		{
+			Con_Printf ("No demos listed with startdemos\n");
+			cls.demonum = -1;
+			return;
+		}
+	}
+
+	sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
+	Cbuf_InsertText (str);
+	cls.demonum++;
+}
+
+/*
+==============
+CL_PrintEntities_f
+==============
+*/
+void CL_PrintEntities_f (void)
+{
+	entity_t	*ent;
+	int			i;
+	
+	for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)
+	{
+		Con_Printf ("%3i:",i);
+		if (!ent->model)
+		{
+			Con_Printf ("EMPTY\n");
+			continue;
+		}
+		Con_Printf ("%s:%2i  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
+		,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
+	}
+}
+
+
+/*
+===============
+SetPal
+
+Debugging tool, just flashes the screen
+===============
+*/
+void SetPal (int i)
+{
+#if 0
+	static int old;
+	byte	pal[768];
+	int		c;
+	
+	if (i == old)
+		return;
+	old = i;
+
+	if (i==0)
+		VID_SetPalette (host_basepal);
+	else if (i==1)
+	{
+		for (c=0 ; c<768 ; c+=3)
+		{
+			pal[c] = 0;
+			pal[c+1] = 255;
+			pal[c+2] = 0;
+		}
+		VID_SetPalette (pal);
+	}
+	else
+	{
+		for (c=0 ; c<768 ; c+=3)
+		{
+			pal[c] = 0;
+			pal[c+1] = 0;
+			pal[c+2] = 255;
+		}
+		VID_SetPalette (pal);
+	}
+#endif
+}
+
+/*
+===============
+CL_AllocDlight
+
+===============
+*/
+dlight_t *CL_AllocDlight (int key)
+{
+	int		i;
+	dlight_t	*dl;
+
+// first look for an exact key match
+	if (key)
+	{
+		dl = cl_dlights;
+		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+		{
+			if (dl->key == key)
+			{
+				memset (dl, 0, sizeof(*dl));
+				dl->key = key;
+				return dl;
+			}
+		}
+	}
+
+// then look for anything else
+	dl = cl_dlights;
+	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+	{
+		if (dl->die < cl.time)
+		{
+			memset (dl, 0, sizeof(*dl));
+			dl->key = key;
+			return dl;
+		}
+	}
+
+	dl = &cl_dlights[0];
+	memset (dl, 0, sizeof(*dl));
+	dl->key = key;
+	return dl;
+}
+
+
+/*
+===============
+CL_DecayLights
+
+===============
+*/
+void CL_DecayLights (void)
+{
+	int			i;
+	dlight_t	*dl;
+	float		time;
+	
+	time = cl.time - cl.oldtime;
+
+	dl = cl_dlights;
+	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+	{
+		if (dl->die < cl.time || !dl->radius)
+			continue;
+		
+		dl->radius -= time*dl->decay;
+		if (dl->radius < 0)
+			dl->radius = 0;
+	}
+}
+
+
+/*
+===============
+CL_LerpPoint
+
+Determines the fraction between the last two messages that the objects
+should be put at.
+===============
+*/
+float	CL_LerpPoint (void)
+{
+	float	f, frac;
+
+	f = cl.mtime[0] - cl.mtime[1];
+	
+	if (!f || cl_nolerp.value || cls.timedemo || sv.active)
+	{
+		cl.time = cl.mtime[0];
+		return 1;
+	}
+		
+	if (f > 0.1)
+	{	// dropped packet, or start of demo
+		cl.mtime[1] = cl.mtime[0] - 0.1;
+		f = 0.1;
+	}
+	frac = (cl.time - cl.mtime[1]) / f;
+//Con_Printf ("frac: %f\n",frac);
+	if (frac < 0)
+	{
+		if (frac < -0.01)
+		{
+SetPal(1);
+			cl.time = cl.mtime[1];
+//				Con_Printf ("low frac\n");
+		}
+		frac = 0;
+	}
+	else if (frac > 1)
+	{
+		if (frac > 1.01)
+		{
+SetPal(2);
+			cl.time = cl.mtime[0];
+//				Con_Printf ("high frac\n");
+		}
+		frac = 1;
+	}
+	else
+		SetPal(0);
+		
+	return frac;
+}
+
+
+/*
+===============
+CL_RelinkEntities
+===============
+*/
+void CL_RelinkEntities (void)
+{
+	entity_t	*ent;
+	int			i, j;
+	float		frac, f, d;
+	vec3_t		delta;
+	float		bobjrotate;
+	vec3_t		oldorg;
+	dlight_t	*dl;
+
+// determine partial update time	
+	frac = CL_LerpPoint ();
+
+	cl_numvisedicts = 0;
+
+//
+// interpolate player info
+//
+	for (i=0 ; i<3 ; i++)
+		cl.velocity[i] = cl.mvelocity[1][i] + 
+			frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
+
+	if (cls.demoplayback)
+	{
+	// interpolate the angles	
+		for (j=0 ; j<3 ; j++)
+		{
+			d = cl.mviewangles[0][j] - cl.mviewangles[1][j];
+			if (d > 180)
+				d -= 360;
+			else if (d < -180)
+				d += 360;
+			cl.viewangles[j] = cl.mviewangles[1][j] + frac*d;
+		}
+	}
+	
+	bobjrotate = anglemod(100*cl.time);
+	
+// start on the entity after the world
+	for (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++)
+	{
+		if (!ent->model)
+		{	// empty slot
+			if (ent->forcelink)
+				R_RemoveEfrags (ent);	// just became empty
+			continue;
+		}
+
+// if the object wasn't included in the last packet, remove it
+		if (ent->msgtime != cl.mtime[0])
+		{
+			ent->model = NULL;
+			continue;
+		}
+
+		VectorCopy (ent->origin, oldorg);
+
+		if (ent->forcelink)
+		{	// the entity was not updated in the last message
+			// so move to the final spot
+			VectorCopy (ent->msg_origins[0], ent->origin);
+			VectorCopy (ent->msg_angles[0], ent->angles);
+		}
+		else
+		{	// if the delta is large, assume a teleport and don't lerp
+			f = frac;
+			for (j=0 ; j<3 ; j++)
+			{
+				delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
+				if (delta[j] > 100 || delta[j] < -100)
+					f = 1;		// assume a teleportation, not a motion
+			}
+
+		// interpolate the origin and angles
+			for (j=0 ; j<3 ; j++)
+			{
+				ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];
+
+				d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
+				if (d > 180)
+					d -= 360;
+				else if (d < -180)
+					d += 360;
+				ent->angles[j] = ent->msg_angles[1][j] + f*d;
+			}
+			
+		}
+
+// rotate binary objects locally
+		if (ent->model->flags & EF_ROTATE)
+			ent->angles[1] = bobjrotate;
+
+		if (ent->effects & EF_BRIGHTFIELD)
+			R_EntityParticles (ent);
+#ifdef QUAKE2
+		if (ent->effects & EF_DARKFIELD)
+			R_DarkFieldParticles (ent);
+#endif
+		if (ent->effects & EF_MUZZLEFLASH)
+		{
+			vec3_t		fv, rv, uv;
+
+			dl = CL_AllocDlight (i);
+			VectorCopy (ent->origin,  dl->origin);
+			dl->origin[2] += 16;
+			AngleVectors (ent->angles, fv, rv, uv);
+			 
+			VectorMA (dl->origin, 18, fv, dl->origin);
+			dl->radius = 200 + (rand()&31);
+			dl->minlight = 32;
+			dl->die = cl.time + 0.1;
+		}
+		if (ent->effects & EF_BRIGHTLIGHT)
+		{			
+			dl = CL_AllocDlight (i);
+			VectorCopy (ent->origin,  dl->origin);
+			dl->origin[2] += 16;
+			dl->radius = 400 + (rand()&31);
+			dl->die = cl.time + 0.001;
+		}
+		if (ent->effects & EF_DIMLIGHT)
+		{			
+			dl = CL_AllocDlight (i);
+			VectorCopy (ent->origin,  dl->origin);
+			dl->radius = 200 + (rand()&31);
+			dl->die = cl.time + 0.001;
+		}
+#ifdef QUAKE2
+		if (ent->effects & EF_DARKLIGHT)
+		{			
+			dl = CL_AllocDlight (i);
+			VectorCopy (ent->origin,  dl->origin);
+			dl->radius = 200.0 + (rand()&31);
+			dl->die = cl.time + 0.001;
+			dl->dark = true;
+		}
+		if (ent->effects & EF_LIGHT)
+		{			
+			dl = CL_AllocDlight (i);
+			VectorCopy (ent->origin,  dl->origin);
+			dl->radius = 200;
+			dl->die = cl.time + 0.001;
+		}
+#endif
+
+		if (ent->model->flags & EF_GIB)
+			R_RocketTrail (oldorg, ent->origin, 2);
+		else if (ent->model->flags & EF_ZOMGIB)
+			R_RocketTrail (oldorg, ent->origin, 4);
+		else if (ent->model->flags & EF_TRACER)
+			R_RocketTrail (oldorg, ent->origin, 3);
+		else if (ent->model->flags & EF_TRACER2)
+			R_RocketTrail (oldorg, ent->origin, 5);
+		else if (ent->model->flags & EF_ROCKET)
+		{
+			R_RocketTrail (oldorg, ent->origin, 0);
+			dl = CL_AllocDlight (i);
+			VectorCopy (ent->origin, dl->origin);
+			dl->radius = 200;
+			dl->die = cl.time + 0.01;
+		}
+		else if (ent->model->flags & EF_GRENADE)
+			R_RocketTrail (oldorg, ent->origin, 1);
+		else if (ent->model->flags & EF_TRACER3)
+			R_RocketTrail (oldorg, ent->origin, 6);
+
+		ent->forcelink = false;
+
+		if (i == cl.viewentity && !chase_active.value)
+			continue;
+
+#ifdef QUAKE2
+		if ( ent->effects & EF_NODRAW )
+			continue;
+#endif
+		if (cl_numvisedicts < MAX_VISEDICTS)
+		{
+			cl_visedicts[cl_numvisedicts] = ent;
+			cl_numvisedicts++;
+		}
+	}
+
+}
+
+
+/*
+===============
+CL_ReadFromServer
+
+Read all incoming data from the server
+===============
+*/
+int CL_ReadFromServer (void)
+{
+	int		ret;
+
+	cl.oldtime = cl.time;
+	cl.time += host_frametime;
+	
+	do
+	{
+		ret = CL_GetMessage ();
+		if (ret == -1)
+			Host_Error ("CL_ReadFromServer: lost server connection");
+		if (!ret)
+			break;
+		
+		cl.last_received_message = realtime;
+		CL_ParseServerMessage ();
+	} while (ret && cls.state == ca_connected);
+	
+	if (cl_shownet.value)
+		Con_Printf ("\n");
+
+	CL_RelinkEntities ();
+	CL_UpdateTEnts ();
+
+//
+// bring the links up to date
+//
+	return 0;
+}
+
+/*
+=================
+CL_SendCmd
+=================
+*/
+void CL_SendCmd (void)
+{
+	usercmd_t		cmd;
+
+	if (cls.state != ca_connected)
+		return;
+
+	if (cls.signon == SIGNONS)
+	{
+	// get basic movement from keyboard
+		CL_BaseMove (&cmd);
+	
+	// allow mice or other external controllers to add to the move
+		IN_Move (&cmd);
+	
+	// send the unreliable message
+		CL_SendMove (&cmd);
+	
+	}
+
+	if (cls.demoplayback)
+	{
+		SZ_Clear (&cls.message);
+		return;
+	}
+	
+// send the reliable message
+	if (!cls.message.cursize)
+		return;		// no message at all
+	
+	if (!NET_CanSendMessage (cls.netcon))
+	{
+		Con_DPrintf ("CL_WriteToServer: can't send\n");
+		return;
+	}
+
+	if (NET_SendMessage (cls.netcon, &cls.message) == -1)
+		Host_Error ("CL_WriteToServer: lost server connection");
+
+	SZ_Clear (&cls.message);
+}
+
+/*
+=================
+CL_Init
+=================
+*/
+void CL_Init (void)
+{	
+	SZ_Alloc (&cls.message, 1024);
+
+	CL_InitInput ();
+	CL_InitTEnts ();
+	
+//
+// register our commands
+//
+	Cvar_RegisterVariable (&cl_name);
+	Cvar_RegisterVariable (&cl_color);
+	Cvar_RegisterVariable (&cl_upspeed);
+	Cvar_RegisterVariable (&cl_forwardspeed);
+	Cvar_RegisterVariable (&cl_backspeed);
+	Cvar_RegisterVariable (&cl_sidespeed);
+	Cvar_RegisterVariable (&cl_movespeedkey);
+	Cvar_RegisterVariable (&cl_yawspeed);
+	Cvar_RegisterVariable (&cl_pitchspeed);
+	Cvar_RegisterVariable (&cl_anglespeedkey);
+	Cvar_RegisterVariable (&cl_shownet);
+	Cvar_RegisterVariable (&cl_nolerp);
+	Cvar_RegisterVariable (&lookspring);
+	Cvar_RegisterVariable (&lookstrafe);
+	Cvar_RegisterVariable (&sensitivity);
+
+	Cvar_RegisterVariable (&m_pitch);
+	Cvar_RegisterVariable (&m_yaw);
+	Cvar_RegisterVariable (&m_forward);
+	Cvar_RegisterVariable (&m_side);
+
+//	Cvar_RegisterVariable (&cl_autofire);
+	
+	Cmd_AddCommand ("entities", CL_PrintEntities_f);
+	Cmd_AddCommand ("disconnect", CL_Disconnect_f);
+	Cmd_AddCommand ("record", CL_Record_f);
+	Cmd_AddCommand ("stop", CL_Stop_f);
+	Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
+	Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
+}
+
diff --git a/quake/src/WinQuake/cl_parse.c b/quake/src/WinQuake/cl_parse.cpp
old mode 100644
new mode 100755
similarity index 98%
rename from quake/src/WinQuake/cl_parse.c
rename to quake/src/WinQuake/cl_parse.cpp
index 528c254..7dbdf05
--- a/quake/src/WinQuake/cl_parse.c
+++ b/quake/src/WinQuake/cl_parse.cpp
@@ -1,27 +1,27 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // cl_parse.c  -- parse a message received from the server
 
 #include "quakedef.h"
 
-char *svc_strings[] =
+const char *svc_strings[] =
 {
 	"svc_bad",
 	"svc_nop",
@@ -230,7 +230,7 @@
 		Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
 		return;
 	}
-	cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
+	cl.scores = (scoreboard_t*) Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
 
 // parse gametype
 	cl.gametype = MSG_ReadByte ();
@@ -936,26 +936,26 @@
 
 		case svc_intermission:
 			cl.intermission = 1;
-			cl.completed_time = cl.time;
+			cl.completed_time = (int) cl.time;
 			vid.recalc_refdef = true;	// go to full screen
 			break;
 
 		case svc_finale:
 			cl.intermission = 2;
-			cl.completed_time = cl.time;
+			cl.completed_time = (int) cl.time;
 			vid.recalc_refdef = true;	// go to full screen
 			SCR_CenterPrint (MSG_ReadString ());			
 			break;
 
 		case svc_cutscene:
 			cl.intermission = 3;
-			cl.completed_time = cl.time;
+			cl.completed_time = (int) cl.time;
 			vid.recalc_refdef = true;	// go to full screen
 			SCR_CenterPrint (MSG_ReadString ());			
 			break;
 
 		case svc_sellscreen:
-			Cmd_ExecuteString ("help", src_command);
+			Cmd_ExecuteString2 ("help", src_command);
 			break;
 		}
 	}
diff --git a/quake/src/WinQuake/cl_tent.c b/quake/src/WinQuake/cl_tent.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/cl_tent.c
rename to quake/src/WinQuake/cl_tent.cpp
diff --git a/quake/src/WinQuake/clean.bat b/quake/src/WinQuake/clean.bat
old mode 100755
new mode 100644
diff --git a/quake/src/WinQuake/client.h b/quake/src/WinQuake/client.h
index 2da1c67..9aafd0c 100644
--- a/quake/src/WinQuake/client.h
+++ b/quake/src/WinQuake/client.h
@@ -1,375 +1,376 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// client.h

-

-typedef struct

-{

-	vec3_t	viewangles;

-

-// intended velocities

-	float	forwardmove;

-	float	sidemove;

-	float	upmove;

-#ifdef QUAKE2

-	byte	lightlevel;

-#endif

-} usercmd_t;

-

-typedef struct

-{

-	int		length;

-	char	map[MAX_STYLESTRING];

-} lightstyle_t;

-

-typedef struct

-{

-	char	name[MAX_SCOREBOARDNAME];

-	float	entertime;

-	int		frags;

-	int		colors;			// two 4 bit fields

-	byte	translations[VID_GRADES*256];

-} scoreboard_t;

-

-typedef struct

-{

-	int		destcolor[3];

-	int		percent;		// 0-256

-} cshift_t;

-

-#define	CSHIFT_CONTENTS	0

-#define	CSHIFT_DAMAGE	1

-#define	CSHIFT_BONUS	2

-#define	CSHIFT_POWERUP	3

-#define	NUM_CSHIFTS		4

-

-#define	NAME_LENGTH	64

-

-

-//

-// client_state_t should hold all pieces of the client state

-//

-

-#define	SIGNONS		4			// signon messages to receive before connected

-

-#define	MAX_DLIGHTS		32

-typedef struct

-{

-	vec3_t	origin;

-	float	radius;

-	float	die;				// stop lighting after this time

-	float	decay;				// drop this each second

-	float	minlight;			// don't add when contributing less

-	int		key;

-#ifdef QUAKE2

-	qboolean	dark;			// subtracts light instead of adding

-#endif

-} dlight_t;

-

-

-#define	MAX_BEAMS	24

-typedef struct

-{

-	int		entity;

-	struct model_s	*model;

-	float	endtime;

-	vec3_t	start, end;

-} beam_t;

-

-#define	MAX_EFRAGS		640

-

-#define	MAX_MAPSTRING	2048

-#define	MAX_DEMOS		8

-#define	MAX_DEMONAME	16

-

-typedef enum {

-ca_dedicated, 		// a dedicated server with no ability to start a client

-ca_disconnected, 	// full screen console with no connection

-ca_connected		// valid netcon, talking to a server

-} cactive_t;

-

-//

-// the client_static_t structure is persistant through an arbitrary number

-// of server connections

-//

-typedef struct

-{

-	cactive_t	state;

-

-// personalization data sent to server	

-	char		mapstring[MAX_QPATH];

-	char		spawnparms[MAX_MAPSTRING];	// to restart a level

-

-// demo loop control

-	int			demonum;		// -1 = don't play demos

-	char		demos[MAX_DEMOS][MAX_DEMONAME];		// when not playing

-

-// demo recording info must be here, because record is started before

-// entering a map (and clearing client_state_t)

-	qboolean	demorecording;

-	qboolean	demoplayback;

-	qboolean	timedemo;

-	int			forcetrack;			// -1 = use normal cd track

-	FILE		*demofile;

-	int			td_lastframe;		// to meter out one message a frame

-	int			td_startframe;		// host_framecount at start

-	float		td_starttime;		// realtime at second frame of timedemo

-

-

-// connection information

-	int			signon;			// 0 to SIGNONS

-	struct qsocket_s	*netcon;

-	sizebuf_t	message;		// writing buffer to send to server

-	

-} client_static_t;

-

-extern client_static_t	cls;

-

-//

-// the client_state_t structure is wiped completely at every

-// server signon

-//

-typedef struct

-{

-	int			movemessages;	// since connecting to this server

-								// throw out the first couple, so the player

-								// doesn't accidentally do something the 

-								// first frame

-	usercmd_t	cmd;			// last command sent to the server

-

-// information for local display

-	int			stats[MAX_CL_STATS];	// health, etc

-	int			items;			// inventory bit flags

-	float	item_gettime[32];	// cl.time of aquiring item, for blinking

-	float		faceanimtime;	// use anim frame if cl.time < this

-

-	cshift_t	cshifts[NUM_CSHIFTS];	// color shifts for damage, powerups

-	cshift_t	prev_cshifts[NUM_CSHIFTS];	// and content types

-

-// the client maintains its own idea of view angles, which are

-// sent to the server each frame.  The server sets punchangle when

-// the view is temporarliy offset, and an angle reset commands at the start

-// of each level and after teleporting.

-	vec3_t		mviewangles[2];	// during demo playback viewangles is lerped

-								// between these

-	vec3_t		viewangles;

-	

-	vec3_t		mvelocity[2];	// update by server, used for lean+bob

-								// (0 is newest)

-	vec3_t		velocity;		// lerped between mvelocity[0] and [1]

-

-	vec3_t		punchangle;		// temporary offset

-	

-// pitch drifting vars

-	float		idealpitch;

-	float		pitchvel;

-	qboolean	nodrift;

-	float		driftmove;

-	double		laststop;

-

-	float		viewheight;

-	float		crouch;			// local amount for smoothing stepups

-

-	qboolean	paused;			// send over by server

-	qboolean	onground;

-	qboolean	inwater;

-	

-	int			intermission;	// don't change view angle, full screen, etc

-	int			completed_time;	// latched at intermission start

-	

-	double		mtime[2];		// the timestamp of last two messages	

-	double		time;			// clients view of time, should be between

-								// servertime and oldservertime to generate

-								// a lerp point for other data

-	double		oldtime;		// previous cl.time, time-oldtime is used

-								// to decay light values and smooth step ups

-	

-

-	float		last_received_message;	// (realtime) for net trouble icon

-

-//

-// information that is static for the entire time connected to a server

-//

-	struct model_s		*model_precache[MAX_MODELS];

-	struct sfx_s		*sound_precache[MAX_SOUNDS];

-

-	char		levelname[40];	// for display on solo scoreboard

-	int			viewentity;		// cl_entitites[cl.viewentity] = player

-	int			maxclients;

-	int			gametype;

-

-// refresh related state

-	struct model_s	*worldmodel;	// cl_entitites[0].model

-	struct efrag_s	*free_efrags;

-	int			num_entities;	// held in cl_entities array

-	int			num_statics;	// held in cl_staticentities array

-	entity_t	viewent;			// the gun model

-

-	int			cdtrack, looptrack;	// cd audio

-

-// frag scoreboard

-	scoreboard_t	*scores;		// [cl.maxclients]

-

-#ifdef QUAKE2

-// light level at player's position including dlights

-// this is sent back to the server each frame

-// architectually ugly but it works

-	int			light_level;

-#endif

-} client_state_t;

-

-

-//

-// cvars

-//

-extern	cvar_t	cl_name;

-extern	cvar_t	cl_color;

-

-extern	cvar_t	cl_upspeed;

-extern	cvar_t	cl_forwardspeed;

-extern	cvar_t	cl_backspeed;

-extern	cvar_t	cl_sidespeed;

-

-extern	cvar_t	cl_movespeedkey;

-

-extern	cvar_t	cl_yawspeed;

-extern	cvar_t	cl_pitchspeed;

-

-extern	cvar_t	cl_anglespeedkey;

-

-extern	cvar_t	cl_autofire;

-

-extern	cvar_t	cl_shownet;

-extern	cvar_t	cl_nolerp;

-

-extern	cvar_t	cl_pitchdriftspeed;

-extern	cvar_t	lookspring;

-extern	cvar_t	lookstrafe;

-extern	cvar_t	sensitivity;

-

-extern	cvar_t	m_pitch;

-extern	cvar_t	m_yaw;

-extern	cvar_t	m_forward;

-extern	cvar_t	m_side;

-

-

-#define	MAX_TEMP_ENTITIES	64			// lightning bolts, etc

-#define	MAX_STATIC_ENTITIES	128			// torches, etc

-

-extern	client_state_t	cl;

-

-// FIXME, allocate dynamically

-extern	efrag_t			cl_efrags[MAX_EFRAGS];

-extern	entity_t		cl_entities[MAX_EDICTS];

-extern	entity_t		cl_static_entities[MAX_STATIC_ENTITIES];

-extern	lightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];

-extern	dlight_t		cl_dlights[MAX_DLIGHTS];

-extern	entity_t		cl_temp_entities[MAX_TEMP_ENTITIES];

-extern	beam_t			cl_beams[MAX_BEAMS];

-

-//=============================================================================

-

-//

-// cl_main

-//

-dlight_t *CL_AllocDlight (int key);

-void	CL_DecayLights (void);

-

-void CL_Init (void);

-

-void CL_EstablishConnection (char *host);

-void CL_Signon1 (void);

-void CL_Signon2 (void);

-void CL_Signon3 (void);

-void CL_Signon4 (void);

-

-void CL_Disconnect (void);

-void CL_Disconnect_f (void);

-void CL_NextDemo (void);

-

-#define			MAX_VISEDICTS	256

-extern	int				cl_numvisedicts;

-extern	entity_t		*cl_visedicts[MAX_VISEDICTS];

-

-//

-// cl_input

-//

-typedef struct

-{

-	int		down[2];		// key nums holding it down

-	int		state;			// low bit is down state

-} kbutton_t;

-

-extern	kbutton_t	in_mlook, in_klook;

-extern 	kbutton_t 	in_strafe;

-extern 	kbutton_t 	in_speed;

-

-void CL_InitInput (void);

-void CL_SendCmd (void);

-void CL_SendMove (usercmd_t *cmd);

-

-void CL_ParseTEnt (void);

-void CL_UpdateTEnts (void);

-

-void CL_ClearState (void);

-

-

-int  CL_ReadFromServer (void);

-void CL_WriteToServer (usercmd_t *cmd);

-void CL_BaseMove (usercmd_t *cmd);

-

-

-float CL_KeyState (kbutton_t *key);

-char *Key_KeynumToString (int keynum);

-

-//

-// cl_demo.c

-//

-void CL_StopPlayback (void);

-int CL_GetMessage (void);

-

-void CL_Stop_f (void);

-void CL_Record_f (void);

-void CL_PlayDemo_f (void);

-void CL_TimeDemo_f (void);

-

-//

-// cl_parse.c

-//

-void CL_ParseServerMessage (void);

-void CL_NewTranslation (int slot);

-

-//

-// view

-//

-void V_StartPitchDrift (void);

-void V_StopPitchDrift (void);

-

-void V_RenderView (void);

-void V_UpdatePalette (void);

-void V_Register (void);

-void V_ParseDamage (void);

-void V_SetContentsColor (int contents);

-

-

-//

-// cl_tent

-//

-void CL_InitTEnts (void);

-void CL_SignonReply (void);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// client.h
+
+typedef struct
+{
+	vec3_t	viewangles;
+
+// intended velocities
+	float	forwardmove;
+	float	sidemove;
+	float	upmove;
+#ifdef QUAKE2
+	byte	lightlevel;
+#endif
+} usercmd_t;
+
+typedef struct
+{
+	int		length;
+	char	map[MAX_STYLESTRING];
+} lightstyle_t;
+
+typedef struct
+{
+	char	name[MAX_SCOREBOARDNAME];
+	float	entertime;
+	int		frags;
+	int		colors;			// two 4 bit fields
+	byte	translations[VID_GRADES*256];
+} scoreboard_t;
+
+typedef struct
+{
+	int		destcolor[3];
+	int		percent;		// 0-256
+} cshift_t;
+
+#define	CSHIFT_CONTENTS	0
+#define	CSHIFT_DAMAGE	1
+#define	CSHIFT_BONUS	2
+#define	CSHIFT_POWERUP	3
+#define	NUM_CSHIFTS		4
+
+#define	NAME_LENGTH	64
+
+
+//
+// client_state_t should hold all pieces of the client state
+//
+
+#define	SIGNONS		4			// signon messages to receive before connected
+
+#define	MAX_DLIGHTS		32
+typedef struct
+{
+	vec3_t	origin;
+	float	radius;
+	float	die;				// stop lighting after this time
+	float	decay;				// drop this each second
+	float	minlight;			// don't add when contributing less
+	int		key;
+#ifdef QUAKE2
+	qboolean	dark;			// subtracts light instead of adding
+#endif
+} dlight_t;
+
+
+#define	MAX_BEAMS	24
+typedef struct
+{
+	int		entity;
+	struct model_s	*model;
+	float	endtime;
+	vec3_t	start, end;
+} beam_t;
+
+#define	MAX_EFRAGS		640
+
+#define	MAX_MAPSTRING	2048
+#define	MAX_DEMOS		8
+#define	MAX_DEMONAME	16
+
+typedef enum {
+ca_dedicated, 		// a dedicated server with no ability to start a client
+ca_disconnected, 	// full screen console with no connection
+ca_connected,		// valid netcon, talking to a server
+cactive_t_max = 1 << 30
+} cactive_t;
+
+//
+// the client_static_t structure is persistant through an arbitrary number
+// of server connections
+//
+typedef struct
+{
+	cactive_t	state;
+
+// personalization data sent to server	
+	char		mapstring[MAX_QPATH];
+	char		spawnparms[MAX_MAPSTRING];	// to restart a level
+
+// demo loop control
+	int			demonum;		// -1 = don't play demos
+	char		demos[MAX_DEMOS][MAX_DEMONAME];		// when not playing
+
+// demo recording info must be here, because record is started before
+// entering a map (and clearing client_state_t)
+	qboolean	demorecording;
+	qboolean	demoplayback;
+	qboolean	timedemo;
+	int			forcetrack;			// -1 = use normal cd track
+	FILE		*demofile;
+	int			td_lastframe;		// to meter out one message a frame
+	int			td_startframe;		// host_framecount at start
+	float		td_starttime;		// realtime at second frame of timedemo
+
+
+// connection information
+	int			signon;			// 0 to SIGNONS
+	struct qsocket_s	*netcon;
+	sizebuf_t	message;		// writing buffer to send to server
+	
+} client_static_t;
+
+extern client_static_t	cls;
+
+//
+// the client_state_t structure is wiped completely at every
+// server signon
+//
+typedef struct
+{
+	int			movemessages;	// since connecting to this server
+								// throw out the first couple, so the player
+								// doesn't accidentally do something the 
+								// first frame
+	usercmd_t	cmd;			// last command sent to the server
+
+// information for local display
+	int			stats[MAX_CL_STATS];	// health, etc
+	int			items;			// inventory bit flags
+	float	item_gettime[32];	// cl.time of aquiring item, for blinking
+	float		faceanimtime;	// use anim frame if cl.time < this
+
+	cshift_t	cshifts[NUM_CSHIFTS];	// color shifts for damage, powerups
+	cshift_t	prev_cshifts[NUM_CSHIFTS];	// and content types
+
+// the client maintains its own idea of view angles, which are
+// sent to the server each frame.  The server sets punchangle when
+// the view is temporarliy offset, and an angle reset commands at the start
+// of each level and after teleporting.
+	vec3_t		mviewangles[2];	// during demo playback viewangles is lerped
+								// between these
+	vec3_t		viewangles;
+	
+	vec3_t		mvelocity[2];	// update by server, used for lean+bob
+								// (0 is newest)
+	vec3_t		velocity;		// lerped between mvelocity[0] and [1]
+
+	vec3_t		punchangle;		// temporary offset
+	
+// pitch drifting vars
+	float		idealpitch;
+	float		pitchvel;
+	qboolean	nodrift;
+	float		driftmove;
+	double		laststop;
+
+	float		viewheight;
+	float		crouch;			// local amount for smoothing stepups
+
+	qboolean	paused;			// send over by server
+	qboolean	onground;
+	qboolean	inwater;
+	
+	int			intermission;	// don't change view angle, full screen, etc
+	int			completed_time;	// latched at intermission start
+	
+	double		mtime[2];		// the timestamp of last two messages	
+	double		time;			// clients view of time, should be between
+								// servertime and oldservertime to generate
+								// a lerp point for other data
+	double		oldtime;		// previous cl.time, time-oldtime is used
+								// to decay light values and smooth step ups
+	
+
+	float		last_received_message;	// (realtime) for net trouble icon
+
+//
+// information that is static for the entire time connected to a server
+//
+	struct model_s		*model_precache[MAX_MODELS];
+	struct sfx_s		*sound_precache[MAX_SOUNDS];
+
+	char		levelname[40];	// for display on solo scoreboard
+	int			viewentity;		// cl_entitites[cl.viewentity] = player
+	int			maxclients;
+	int			gametype;
+
+// refresh related state
+	struct model_s	*worldmodel;	// cl_entitites[0].model
+	struct efrag_s	*free_efrags;
+	int			num_entities;	// held in cl_entities array
+	int			num_statics;	// held in cl_staticentities array
+	entity_t	viewent;			// the gun model
+
+	int			cdtrack, looptrack;	// cd audio
+
+// frag scoreboard
+	scoreboard_t	*scores;		// [cl.maxclients]
+
+#ifdef QUAKE2
+// light level at player's position including dlights
+// this is sent back to the server each frame
+// architectually ugly but it works
+	int			light_level;
+#endif
+} client_state_t;
+
+
+//
+// cvars
+//
+extern	cvar_t	cl_name;
+extern	cvar_t	cl_color;
+
+extern	cvar_t	cl_upspeed;
+extern	cvar_t	cl_forwardspeed;
+extern	cvar_t	cl_backspeed;
+extern	cvar_t	cl_sidespeed;
+
+extern	cvar_t	cl_movespeedkey;
+
+extern	cvar_t	cl_yawspeed;
+extern	cvar_t	cl_pitchspeed;
+
+extern	cvar_t	cl_anglespeedkey;
+
+extern	cvar_t	cl_autofire;
+
+extern	cvar_t	cl_shownet;
+extern	cvar_t	cl_nolerp;
+
+extern	cvar_t	cl_pitchdriftspeed;
+extern	cvar_t	lookspring;
+extern	cvar_t	lookstrafe;
+extern	cvar_t	sensitivity;
+
+extern	cvar_t	m_pitch;
+extern	cvar_t	m_yaw;
+extern	cvar_t	m_forward;
+extern	cvar_t	m_side;
+
+
+#define	MAX_TEMP_ENTITIES	64			// lightning bolts, etc
+#define	MAX_STATIC_ENTITIES	128			// torches, etc
+
+extern	client_state_t	cl;
+
+// FIXME, allocate dynamically
+extern	efrag_t			cl_efrags[MAX_EFRAGS];
+extern	entity_t		cl_entities[MAX_EDICTS];
+extern	entity_t		cl_static_entities[MAX_STATIC_ENTITIES];
+extern	lightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];
+extern	dlight_t		cl_dlights[MAX_DLIGHTS];
+extern	entity_t		cl_temp_entities[MAX_TEMP_ENTITIES];
+extern	beam_t			cl_beams[MAX_BEAMS];
+
+//=============================================================================
+
+//
+// cl_main
+//
+dlight_t *CL_AllocDlight (int key);
+void	CL_DecayLights (void);
+
+void CL_Init (void);
+
+void CL_EstablishConnection (const char *host);
+void CL_Signon1 (void);
+void CL_Signon2 (void);
+void CL_Signon3 (void);
+void CL_Signon4 (void);
+
+void CL_Disconnect (void);
+void CL_Disconnect_f (void);
+void CL_NextDemo (void);
+
+#define			MAX_VISEDICTS	256
+extern	int				cl_numvisedicts;
+extern	entity_t		*cl_visedicts[MAX_VISEDICTS];
+
+//
+// cl_input
+//
+typedef struct
+{
+	int		down[2];		// key nums holding it down
+	int		state;			// low bit is down state
+} kbutton_t;
+
+extern	kbutton_t	in_mlook, in_klook;
+extern 	kbutton_t 	in_strafe;
+extern 	kbutton_t 	in_speed;
+
+void CL_InitInput (void);
+void CL_SendCmd (void);
+void CL_SendMove (usercmd_t *cmd);
+
+void CL_ParseTEnt (void);
+void CL_UpdateTEnts (void);
+
+void CL_ClearState (void);
+
+
+int  CL_ReadFromServer (void);
+void CL_WriteToServer (usercmd_t *cmd);
+void CL_BaseMove (usercmd_t *cmd);
+
+
+float CL_KeyState (kbutton_t *key);
+const char *Key_KeynumToString (int keynum);
+
+//
+// cl_demo.c
+//
+void CL_StopPlayback (void);
+int CL_GetMessage (void);
+
+void CL_Stop_f (void);
+void CL_Record_f (void);
+void CL_PlayDemo_f (void);
+void CL_TimeDemo_f (void);
+
+//
+// cl_parse.c
+//
+void CL_ParseServerMessage (void);
+void CL_NewTranslation (int slot);
+
+//
+// view
+//
+void V_StartPitchDrift (void);
+void V_StopPitchDrift (void);
+
+void V_RenderView (void);
+void V_UpdatePalette (void);
+void V_Register (void);
+void V_ParseDamage (void);
+void V_SetContentsColor (int contents);
+
+
+//
+// cl_tent
+//
+void CL_InitTEnts (void);
+void CL_SignonReply (void);
diff --git a/quake/src/WinQuake/cmd.c b/quake/src/WinQuake/cmd.cpp
old mode 100644
new mode 100755
similarity index 91%
rename from quake/src/WinQuake/cmd.c
rename to quake/src/WinQuake/cmd.cpp
index db48924..8c938fe
--- a/quake/src/WinQuake/cmd.c
+++ b/quake/src/WinQuake/cmd.cpp
@@ -1,705 +1,712 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// cmd.c -- Quake script command processing module

-

-#include "quakedef.h"

-

-void Cmd_ForwardToServer (void);

-

-#define	MAX_ALIAS_NAME	32

-

-typedef struct cmdalias_s

-{

-	struct cmdalias_s	*next;

-	char	name[MAX_ALIAS_NAME];

-	char	*value;

-} cmdalias_t;

-

-cmdalias_t	*cmd_alias;

-

-int trashtest;

-int *trashspot;

-

-qboolean	cmd_wait;

-

-//=============================================================================

-

-/*

-============

-Cmd_Wait_f

-

-Causes execution of the remainder of the command buffer to be delayed until

-next frame.  This allows commands like:

-bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"

-============

-*/

-void Cmd_Wait_f (void)

-{

-	cmd_wait = true;

-}

-

-/*

-=============================================================================

-

-						COMMAND BUFFER

-

-=============================================================================

-*/

-

-sizebuf_t	cmd_text;

-

-/*

-============

-Cbuf_Init

-============

-*/

-void Cbuf_Init (void)

-{

-	SZ_Alloc (&cmd_text, 8192);		// space for commands and script files

-}

-

-

-/*

-============

-Cbuf_AddText

-

-Adds command text at the end of the buffer

-============

-*/

-void Cbuf_AddText (char *text)

-{

-	int		l;

-	

-	l = Q_strlen (text);

-

-	if (cmd_text.cursize + l >= cmd_text.maxsize)

-	{

-		Con_Printf ("Cbuf_AddText: overflow\n");

-		return;

-	}

-

-	SZ_Write (&cmd_text, text, Q_strlen (text));

-}

-

-

-/*

-============

-Cbuf_InsertText

-

-Adds command text immediately after the current command

-Adds a \n to the text

-FIXME: actually change the command buffer to do less copying

-============

-*/

-void Cbuf_InsertText (char *text)

-{

-	char	*temp;

-	int		templen;

-

-// copy off any commands still remaining in the exec buffer

-	templen = cmd_text.cursize;

-	if (templen)

-	{

-		temp = Z_Malloc (templen);

-		Q_memcpy (temp, cmd_text.data, templen);

-		SZ_Clear (&cmd_text);

-	}

-	else

-		temp = NULL;	// shut up compiler

-		

-// add the entire text of the file

-	Cbuf_AddText (text);

-	

-// add the copied off data

-	if (templen)

-	{

-		SZ_Write (&cmd_text, temp, templen);

-		Z_Free (temp);

-	}

-}

-

-/*

-============

-Cbuf_Execute

-============

-*/

-void Cbuf_Execute (void)

-{

-	int		i;

-	char	*text;

-	char	line[1024];

-	int		quotes;

-	

-	while (cmd_text.cursize)

-	{

-// find a \n or ; line break

-		text = (char *)cmd_text.data;

-

-		quotes = 0;

-		for (i=0 ; i< cmd_text.cursize ; i++)

-		{

-			if (text[i] == '"')

-				quotes++;

-			if ( !(quotes&1) &&  text[i] == ';')

-				break;	// don't break if inside a quoted string

-			if (text[i] == '\n')

-				break;

-		}

-			

-				

-		memcpy (line, text, i);

-		line[i] = 0;

-		

-// delete the text from the command buffer and move remaining commands down

-// this is necessary because commands (exec, alias) can insert data at the

-// beginning of the text buffer

-

-		if (i == cmd_text.cursize)

-			cmd_text.cursize = 0;

-		else

-		{

-			i++;

-			cmd_text.cursize -= i;

-			Q_memcpy (text, text+i, cmd_text.cursize);

-		}

-

-// execute the command line

-		Cmd_ExecuteString (line, src_command);

-		

-		if (cmd_wait)

-		{	// skip out while text still remains in buffer, leaving it

-			// for next frame

-			cmd_wait = false;

-			break;

-		}

-	}

-}

-

-/*

-==============================================================================

-

-						SCRIPT COMMANDS

-

-==============================================================================

-*/

-

-/*

-===============

-Cmd_StuffCmds_f

-

-Adds command line parameters as script statements

-Commands lead with a +, and continue until a - or another +

-quake +prog jctest.qp +cmd amlev1

-quake -nosound +cmd amlev1

-===============

-*/

-void Cmd_StuffCmds_f (void)

-{

-	int		i, j;

-	int		s;

-	char	*text, *build, c;

-		

-	if (Cmd_Argc () != 1)

-	{

-		Con_Printf ("stuffcmds : execute command line parameters\n");

-		return;

-	}

-

-// build the combined string to parse from

-	s = 0;

-	for (i=1 ; i<com_argc ; i++)

-	{

-		if (!com_argv[i])

-			continue;		// NEXTSTEP nulls out -NXHost

-		s += Q_strlen (com_argv[i]) + 1;

-	}

-	if (!s)

-		return;

-		

-	text = Z_Malloc (s+1);

-	text[0] = 0;

-	for (i=1 ; i<com_argc ; i++)

-	{

-		if (!com_argv[i])

-			continue;		// NEXTSTEP nulls out -NXHost

-		Q_strcat (text,com_argv[i]);

-		if (i != com_argc-1)

-			Q_strcat (text, " ");

-	}

-	

-// pull out the commands

-	build = Z_Malloc (s+1);

-	build[0] = 0;

-	

-	for (i=0 ; i<s-1 ; i++)

-	{

-		if (text[i] == '+')

-		{

-			i++;

-

-			for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)

-				;

-

-			c = text[j];

-			text[j] = 0;

-			

-			Q_strcat (build, text+i);

-			Q_strcat (build, "\n");

-			text[j] = c;

-			i = j-1;

-		}

-	}

-	

-	if (build[0])

-		Cbuf_InsertText (build);

-	

-	Z_Free (text);

-	Z_Free (build);

-}

-

-

-/*

-===============

-Cmd_Exec_f

-===============

-*/

-void Cmd_Exec_f (void)

-{

-	char	*f;

-	int		mark;

-

-	if (Cmd_Argc () != 2)

-	{

-		Con_Printf ("exec <filename> : execute a script file\n");

-		return;

-	}

-

-	mark = Hunk_LowMark ();

-	f = (char *)COM_LoadHunkFile (Cmd_Argv(1));

-	if (!f)

-	{

-		Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));

-		return;

-	}

-	Con_Printf ("execing %s\n",Cmd_Argv(1));

-	

-	Cbuf_InsertText (f);

-	Hunk_FreeToLowMark (mark);

-}

-

-

-/*

-===============

-Cmd_Echo_f

-

-Just prints the rest of the line to the console

-===============

-*/

-void Cmd_Echo_f (void)

-{

-	int		i;

-	

-	for (i=1 ; i<Cmd_Argc() ; i++)

-		Con_Printf ("%s ",Cmd_Argv(i));

-	Con_Printf ("\n");

-}

-

-/*

-===============

-Cmd_Alias_f

-

-Creates a new command that executes a command string (possibly ; seperated)

-===============

-*/

-

-char *CopyString (char *in)

-{

-	char	*out;

-	

-	out = Z_Malloc (strlen(in)+1);

-	strcpy (out, in);

-	return out;

-}

-

-void Cmd_Alias_f (void)

-{

-	cmdalias_t	*a;

-	char		cmd[1024];

-	int			i, c;

-	char		*s;

-

-	if (Cmd_Argc() == 1)

-	{

-		Con_Printf ("Current alias commands:\n");

-		for (a = cmd_alias ; a ; a=a->next)

-			Con_Printf ("%s : %s\n", a->name, a->value);

-		return;

-	}

-

-	s = Cmd_Argv(1);

-	if (strlen(s) >= MAX_ALIAS_NAME)

-	{

-		Con_Printf ("Alias name is too long\n");

-		return;

-	}

-

-	// if the alias allready exists, reuse it

-	for (a = cmd_alias ; a ; a=a->next)

-	{

-		if (!strcmp(s, a->name))

-		{

-			Z_Free (a->value);

-			break;

-		}

-	}

-

-	if (!a)

-	{

-		a = Z_Malloc (sizeof(cmdalias_t));

-		a->next = cmd_alias;

-		cmd_alias = a;

-	}

-	strcpy (a->name, s);	

-

-// copy the rest of the command line

-	cmd[0] = 0;		// start out with a null string

-	c = Cmd_Argc();

-	for (i=2 ; i< c ; i++)

-	{

-		strcat (cmd, Cmd_Argv(i));

-		if (i != c)

-			strcat (cmd, " ");

-	}

-	strcat (cmd, "\n");

-	

-	a->value = CopyString (cmd);

-}

-

-/*

-=============================================================================

-

-					COMMAND EXECUTION

-

-=============================================================================

-*/

-

-typedef struct cmd_function_s

-{

-	struct cmd_function_s	*next;

-	char					*name;

-	xcommand_t				function;

-} cmd_function_t;

-

-

-#define	MAX_ARGS		80

-

-static	int			cmd_argc;

-static	char		*cmd_argv[MAX_ARGS];

-static	char		*cmd_null_string = "";

-static	char		*cmd_args = NULL;

-

-cmd_source_t	cmd_source;

-

-

-static	cmd_function_t	*cmd_functions;		// possible commands to execute

-

-/*

-============

-Cmd_Init

-============

-*/

-void Cmd_Init (void)

-{

-//

-// register our commands

-//

-	Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);

-	Cmd_AddCommand ("exec",Cmd_Exec_f);

-	Cmd_AddCommand ("echo",Cmd_Echo_f);

-	Cmd_AddCommand ("alias",Cmd_Alias_f);

-	Cmd_AddCommand ("cmd", Cmd_ForwardToServer);

-	Cmd_AddCommand ("wait", Cmd_Wait_f);

-}

-

-/*

-============

-Cmd_Argc

-============

-*/

-int		Cmd_Argc (void)

-{

-	return cmd_argc;

-}

-

-/*

-============

-Cmd_Argv

-============

-*/

-char	*Cmd_Argv (int arg)

-{

-	if ( (unsigned)arg >= cmd_argc )

-		return cmd_null_string;

-	return cmd_argv[arg];	

-}

-

-/*

-============

-Cmd_Args

-============

-*/

-char		*Cmd_Args (void)

-{

-	return cmd_args;

-}

-

-

-/*

-============

-Cmd_TokenizeString

-

-Parses the given string into command line tokens.

-============

-*/

-void Cmd_TokenizeString (char *text)

-{

-	int		i;

-	

-// clear the args from the last string

-	for (i=0 ; i<cmd_argc ; i++)

-		Z_Free (cmd_argv[i]);

-		

-	cmd_argc = 0;

-	cmd_args = NULL;

-	

-	while (1)

-	{

-// skip whitespace up to a /n

-		while (*text && *text <= ' ' && *text != '\n')

-		{

-			text++;

-		}

-		

-		if (*text == '\n')

-		{	// a newline seperates commands in the buffer

-			text++;

-			break;

-		}

-

-		if (!*text)

-			return;

-	

-		if (cmd_argc == 1)

-			 cmd_args = text;

-			

-		text = COM_Parse (text);

-		if (!text)

-			return;

-

-		if (cmd_argc < MAX_ARGS)

-		{

-			cmd_argv[cmd_argc] = Z_Malloc (Q_strlen(com_token)+1);

-			Q_strcpy (cmd_argv[cmd_argc], com_token);

-			cmd_argc++;

-		}

-	}

-	

-}

-

-

-/*

-============

-Cmd_AddCommand

-============

-*/

-void	Cmd_AddCommand (char *cmd_name, xcommand_t function)

-{

-	cmd_function_t	*cmd;

-	

-	if (host_initialized)	// because hunk allocation would get stomped

-		Sys_Error ("Cmd_AddCommand after host_initialized");

-		

-// fail if the command is a variable name

-	if (Cvar_VariableString(cmd_name)[0])

-	{

-		Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);

-		return;

-	}

-	

-// fail if the command already exists

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-	{

-		if (!Q_strcmp (cmd_name, cmd->name))

-		{

-			Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);

-			return;

-		}

-	}

-

-	cmd = Hunk_Alloc (sizeof(cmd_function_t));

-	cmd->name = cmd_name;

-	cmd->function = function;

-	cmd->next = cmd_functions;

-	cmd_functions = cmd;

-}

-

-/*

-============

-Cmd_Exists

-============

-*/

-qboolean	Cmd_Exists (char *cmd_name)

-{

-	cmd_function_t	*cmd;

-

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-	{

-		if (!Q_strcmp (cmd_name,cmd->name))

-			return true;

-	}

-

-	return false;

-}

-

-

-

-/*

-============

-Cmd_CompleteCommand

-============

-*/

-char *Cmd_CompleteCommand (char *partial)

-{

-	cmd_function_t	*cmd;

-	int				len;

-	

-	len = Q_strlen(partial);

-	

-	if (!len)

-		return NULL;

-		

-// check functions

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-		if (!Q_strncmp (partial,cmd->name, len))

-			return cmd->name;

-

-	return NULL;

-}

-

-/*

-============

-Cmd_ExecuteString

-

-A complete command line has been parsed, so try to execute it

-FIXME: lookupnoadd the token to speed search?

-============

-*/

-void	Cmd_ExecuteString (char *text, cmd_source_t src)

-{	

-	cmd_function_t	*cmd;

-	cmdalias_t		*a;

-

-	cmd_source = src;

-	Cmd_TokenizeString (text);

-			

-// execute the command line

-	if (!Cmd_Argc())

-		return;		// no tokens

-

-// check functions

-	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)

-	{

-		if (!Q_strcasecmp (cmd_argv[0],cmd->name))

-		{

-			cmd->function ();

-			return;

-		}

-	}

-

-// check alias

-	for (a=cmd_alias ; a ; a=a->next)

-	{

-		if (!Q_strcasecmp (cmd_argv[0], a->name))

-		{

-			Cbuf_InsertText (a->value);

-			return;

-		}

-	}

-	

-// check cvars

-	if (!Cvar_Command ())

-		Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));

-	

-}

-

-

-/*

-===================

-Cmd_ForwardToServer

-

-Sends the entire command line over to the server

-===================

-*/

-void Cmd_ForwardToServer (void)

-{

-	if (cls.state != ca_connected)

-	{

-		Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));

-		return;

-	}

-	

-	if (cls.demoplayback)

-		return;		// not really connected

-

-	MSG_WriteByte (&cls.message, clc_stringcmd);

-	if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0)

-	{

-		SZ_Print (&cls.message, Cmd_Argv(0));

-		SZ_Print (&cls.message, " ");

-	}

-	if (Cmd_Argc() > 1)

-		SZ_Print (&cls.message, Cmd_Args());

-	else

-		SZ_Print (&cls.message, "\n");

-}

-

-

-/*

-================

-Cmd_CheckParm

-

-Returns the position (1 to argc-1) in the command's argument list

-where the given parameter apears, or 0 if not present

-================

-*/

-

-int Cmd_CheckParm (char *parm)

-{

-	int i;

-	

-	if (!parm)

-		Sys_Error ("Cmd_CheckParm: NULL");

-

-	for (i = 1; i < Cmd_Argc (); i++)

-		if (! Q_strcasecmp (parm, Cmd_Argv (i)))

-			return i;

-			

-	return 0;

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// cmd.c -- Quake script command processing module
+
+#include "quakedef.h"
+
+void Cmd_ForwardToServer (void);
+
+#define	MAX_ALIAS_NAME	32
+
+typedef struct cmdalias_s
+{
+	struct cmdalias_s	*next;
+	char	name[MAX_ALIAS_NAME];
+	char	*value;
+} cmdalias_t;
+
+cmdalias_t	*cmd_alias;
+
+int trashtest;
+int *trashspot;
+
+qboolean	cmd_wait;
+
+//=============================================================================
+
+/*
+============
+Cmd_Wait_f
+
+Causes execution of the remainder of the command buffer to be delayed until
+next frame.  This allows commands like:
+bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
+============
+*/
+void Cmd_Wait_f (void)
+{
+	cmd_wait = true;
+}
+
+/*
+=============================================================================
+
+						COMMAND BUFFER
+
+=============================================================================
+*/
+
+sizebuf_t	cmd_text;
+
+/*
+============
+Cbuf_Init
+============
+*/
+void Cbuf_Init (void)
+{
+	SZ_Alloc (&cmd_text, 8192);		// space for commands and script files
+}
+
+
+/*
+============
+Cbuf_AddText
+
+Adds command text at the end of the buffer
+============
+*/
+void Cbuf_AddText (const char *text)
+{
+	int		l;
+	
+	l = Q_strlen (text);
+
+	if (cmd_text.cursize + l >= cmd_text.maxsize)
+	{
+		Con_Printf ("Cbuf_AddText: overflow\n");
+		return;
+	}
+
+	SZ_Write (&cmd_text, text, Q_strlen (text));
+}
+
+
+/*
+============
+Cbuf_InsertText
+
+Adds command text immediately after the current command
+Adds a \n to the text
+FIXME: actually change the command buffer to do less copying
+============
+*/
+void Cbuf_InsertText (const char *text)
+{
+	char	*temp;
+	int		templen;
+
+// copy off any commands still remaining in the exec buffer
+	templen = cmd_text.cursize;
+	if (templen)
+	{
+		temp = (char*) Z_Malloc (templen);
+		Q_memcpy (temp, cmd_text.data, templen);
+		SZ_Clear (&cmd_text);
+	}
+	else
+		temp = NULL;	// shut up compiler
+		
+// add the entire text of the file
+	Cbuf_AddText (text);
+	
+// add the copied off data
+	if (templen)
+	{
+		SZ_Write (&cmd_text, temp, templen);
+		Z_Free (temp);
+	}
+}
+
+/*
+============
+Cbuf_Execute
+============
+*/
+void Cbuf_Execute (void)
+{
+	int		i;
+	char	*text;
+	char	line[1024];
+	int		quotes;
+	
+	while (cmd_text.cursize)
+	{
+// find a \n or ; line break
+		text = (char *)cmd_text.data;
+
+		quotes = 0;
+		for (i=0 ; i< cmd_text.cursize ; i++)
+		{
+			if (text[i] == '"')
+				quotes++;
+			if ( !(quotes&1) &&  text[i] == ';')
+				break;	// don't break if inside a quoted string
+			if (text[i] == '\n' || text[i] == '\r')
+				break;
+		}
+			
+				
+		memcpy (line, text, i);
+		line[i] = 0;
+		
+// delete the text from the command buffer and move remaining commands down
+// this is necessary because commands (exec, alias) can insert data at the
+// beginning of the text buffer
+
+		if (i == cmd_text.cursize)
+			cmd_text.cursize = 0;
+		else
+		{
+			i++;
+			cmd_text.cursize -= i;
+			Q_memcpy (text, text+i, cmd_text.cursize);
+		}
+
+// execute the command line
+		Cmd_ExecuteString (line, src_command);
+		
+		if (cmd_wait)
+		{	// skip out while text still remains in buffer, leaving it
+			// for next frame
+			cmd_wait = false;
+			break;
+		}
+	}
+}
+
+/*
+==============================================================================
+
+						SCRIPT COMMANDS
+
+==============================================================================
+*/
+
+/*
+===============
+Cmd_StuffCmds_f
+
+Adds command line parameters as script statements
+Commands lead with a +, and continue until a - or another +
+quake +prog jctest.qp +cmd amlev1
+quake -nosound +cmd amlev1
+===============
+*/
+void Cmd_StuffCmds_f (void)
+{
+	int		i, j;
+	int		s;
+	char	*text, *build, c;
+		
+	if (Cmd_Argc () != 1)
+	{
+		Con_Printf ("stuffcmds : execute command line parameters\n");
+		return;
+	}
+
+// build the combined string to parse from
+	s = 0;
+	for (i=1 ; i<com_argc ; i++)
+	{
+		if (!com_argv[i])
+			continue;		// NEXTSTEP nulls out -NXHost
+		s += Q_strlen (com_argv[i]) + 1;
+	}
+	if (!s)
+		return;
+		
+	text = (char*) Z_Malloc (s+1);
+	text[0] = 0;
+	for (i=1 ; i<com_argc ; i++)
+	{
+		if (!com_argv[i])
+			continue;		// NEXTSTEP nulls out -NXHost
+		Q_strcat (text,com_argv[i]);
+		if (i != com_argc-1)
+			Q_strcat (text, " ");
+	}
+	
+// pull out the commands
+	build = (char*) Z_Malloc (s+1);
+	build[0] = 0;
+	
+	for (i=0 ; i<s-1 ; i++)
+	{
+		if (text[i] == '+')
+		{
+			i++;
+
+			for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
+				;
+
+			c = text[j];
+			text[j] = 0;
+			
+			Q_strcat (build, text+i);
+			Q_strcat (build, "\n");
+			text[j] = c;
+			i = j-1;
+		}
+	}
+	
+	if (build[0])
+		Cbuf_InsertText (build);
+	
+	Z_Free (text);
+	Z_Free (build);
+}
+
+
+/*
+===============
+Cmd_Exec_f
+===============
+*/
+void Cmd_Exec_f (void)
+{
+	char	*f;
+	int		mark;
+
+	if (Cmd_Argc () != 2)
+	{
+		Con_Printf ("exec <filename> : execute a script file\n");
+		return;
+	}
+
+	mark = Hunk_LowMark ();
+	f = (char *)COM_LoadHunkFile (Cmd_Argv(1));
+	if (!f)
+	{
+		Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
+		return;
+	}
+	Con_Printf ("execing %s\n",Cmd_Argv(1));
+	
+	Cbuf_InsertText (f);
+	Hunk_FreeToLowMark (mark);
+}
+
+
+/*
+===============
+Cmd_Echo_f
+
+Just prints the rest of the line to the console
+===============
+*/
+void Cmd_Echo_f (void)
+{
+	int		i;
+	
+	for (i=1 ; i<Cmd_Argc() ; i++)
+		Con_Printf ("%s ",Cmd_Argv(i));
+	Con_Printf ("\n");
+}
+
+/*
+===============
+Cmd_Alias_f
+
+Creates a new command that executes a command string (possibly ; seperated)
+===============
+*/
+
+char *CopyString (const char *in)
+{
+	char	*out;
+	
+	out = (char*) Z_Malloc (strlen(in)+1);
+	strcpy (out, in);
+	return out;
+}
+
+void Cmd_Alias_f (void)
+{
+	cmdalias_t	*a;
+	char		cmd[1024];
+	int			i, c;
+	const char		*s;
+
+	if (Cmd_Argc() == 1)
+	{
+		Con_Printf ("Current alias commands:\n");
+		for (a = cmd_alias ; a ; a=a->next)
+			Con_Printf ("%s : %s\n", a->name, a->value);
+		return;
+	}
+
+	s = Cmd_Argv(1);
+	if (strlen(s) >= MAX_ALIAS_NAME)
+	{
+		Con_Printf ("Alias name is too long\n");
+		return;
+	}
+
+	// if the alias allready exists, reuse it
+	for (a = cmd_alias ; a ; a=a->next)
+	{
+		if (!strcmp(s, a->name))
+		{
+			Z_Free (a->value);
+			break;
+		}
+	}
+
+	if (!a)
+	{
+		a = (cmdalias_t*) Z_Malloc (sizeof(cmdalias_t));
+		a->next = cmd_alias;
+		cmd_alias = a;
+	}
+	strcpy (a->name, s);	
+
+// copy the rest of the command line
+	cmd[0] = 0;		// start out with a null string
+	c = Cmd_Argc();
+	for (i=2 ; i< c ; i++)
+	{
+		strcat (cmd, Cmd_Argv(i));
+		if (i != c)
+			strcat (cmd, " ");
+	}
+	strcat (cmd, "\n");
+	
+	a->value = CopyString (cmd);
+}
+
+/*
+=============================================================================
+
+					COMMAND EXECUTION
+
+=============================================================================
+*/
+
+typedef struct cmd_function_s
+{
+	struct cmd_function_s	*next;
+	char					*name;
+	xcommand_t				function;
+} cmd_function_t;
+
+
+#define	MAX_ARGS		80
+
+static	int			cmd_argc;
+static	char		*cmd_argv[MAX_ARGS];
+static	char		*cmd_null_string = (char*) "";
+static	char		*cmd_args = NULL;
+
+cmd_source_t	cmd_source;
+
+
+static	cmd_function_t	*cmd_functions;		// possible commands to execute
+
+/*
+============
+Cmd_Init
+============
+*/
+void Cmd_Init (void)
+{
+//
+// register our commands
+//
+	Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
+	Cmd_AddCommand ("exec",Cmd_Exec_f);
+	Cmd_AddCommand ("echo",Cmd_Echo_f);
+	Cmd_AddCommand ("alias",Cmd_Alias_f);
+	Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
+	Cmd_AddCommand ("wait", Cmd_Wait_f);
+}
+
+/*
+============
+Cmd_Argc
+============
+*/
+int		Cmd_Argc (void)
+{
+	return cmd_argc;
+}
+
+/*
+============
+Cmd_Argv
+============
+*/
+char	*Cmd_Argv (int arg)
+{
+	if ( arg >= cmd_argc )
+		return cmd_null_string;
+	return cmd_argv[arg];	
+}
+
+/*
+============
+Cmd_Args
+============
+*/
+char		*Cmd_Args (void)
+{
+	return cmd_args;
+}
+
+
+/*
+============
+Cmd_TokenizeString
+
+Parses the given string into command line tokens.
+============
+*/
+void Cmd_TokenizeString (char *text)
+{
+	int		i;
+	
+// clear the args from the last string
+	for (i=0 ; i<cmd_argc ; i++)
+		Z_Free (cmd_argv[i]);
+		
+	cmd_argc = 0;
+	cmd_args = NULL;
+	
+	while (1)
+	{
+// skip whitespace up to a /n
+		while (*text && *text <= ' ' && *text != '\n')
+		{
+			text++;
+		}
+		
+		if (*text == '\n')
+		{	// a newline seperates commands in the buffer
+			text++;
+			break;
+		}
+
+		if (!*text)
+			return;
+	
+		if (cmd_argc == 1)
+			 cmd_args = text;
+			
+		text = COM_Parse (text);
+		if (!text)
+			return;
+
+		if (cmd_argc < MAX_ARGS)
+		{
+			cmd_argv[cmd_argc] = (char*) Z_Malloc (Q_strlen(com_token)+1);
+			Q_strcpy (cmd_argv[cmd_argc], com_token);
+			cmd_argc++;
+		}
+	}
+	
+}
+
+
+/*
+============
+Cmd_AddCommand
+============
+*/
+void	Cmd_AddCommand (const char *cmd_name, xcommand_t function)
+{
+	cmd_function_t	*cmd;
+	
+	if (host_initialized)	// because hunk allocation would get stomped
+		Sys_Error ("Cmd_AddCommand after host_initialized");
+		
+// fail if the command is a variable name
+	if (Cvar_VariableString(cmd_name)[0])
+	{
+		Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
+		return;
+	}
+	
+// fail if the command already exists
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+	{
+		if (!Q_strcmp (cmd_name, cmd->name))
+		{
+			Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
+			return;
+		}
+	}
+
+	cmd = (cmd_function_t*) Hunk_Alloc (sizeof(cmd_function_t));
+	cmd->name = (char*) cmd_name;
+	cmd->function = function;
+	cmd->next = cmd_functions;
+	cmd_functions = cmd;
+}
+
+/*
+============
+Cmd_Exists
+============
+*/
+qboolean	Cmd_Exists (const char *cmd_name)
+{
+	cmd_function_t	*cmd;
+
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+	{
+		if (!Q_strcmp (cmd_name,cmd->name))
+			return true;
+	}
+
+	return false;
+}
+
+
+
+/*
+============
+Cmd_CompleteCommand
+============
+*/
+const char *Cmd_CompleteCommand (const char *partial)
+{
+	cmd_function_t	*cmd;
+	int				len;
+	
+	len = Q_strlen(partial);
+	
+	if (!len)
+		return NULL;
+		
+// check functions
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+		if (!Q_strncmp (partial,cmd->name, len))
+			return cmd->name;
+
+	return NULL;
+}
+
+/*
+============
+Cmd_ExecuteString
+
+A complete command line has been parsed, so try to execute it
+FIXME: lookupnoadd the token to speed search?
+============
+*/
+void	Cmd_ExecuteString (char *text, cmd_source_t src)
+{	
+	cmd_function_t	*cmd;
+	cmdalias_t		*a;
+
+	cmd_source = src;
+	Cmd_TokenizeString (text);
+			
+// execute the command line
+	if (!Cmd_Argc())
+		return;		// no tokens
+
+// check functions
+	for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+	{
+		if (!Q_strcasecmp (cmd_argv[0],cmd->name))
+		{
+			cmd->function ();
+			return;
+		}
+	}
+
+// check alias
+	for (a=cmd_alias ; a ; a=a->next)
+	{
+		if (!Q_strcasecmp (cmd_argv[0], a->name))
+		{
+			Cbuf_InsertText (a->value);
+			return;
+		}
+	}
+	
+// check cvars
+	if (!Cvar_Command ())
+		Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
+	
+}
+
+void    Cmd_ExecuteString2 (const char *text, cmd_source_t src)
+{
+    char buf[100];
+    Q_strncpy(buf, text, sizeof(buf));
+    buf[sizeof(buf)-1] = 0;
+    Cmd_ExecuteString(buf, src);
+}
+
+/*
+===================
+Cmd_ForwardToServer
+
+Sends the entire command line over to the server
+===================
+*/
+void Cmd_ForwardToServer (void)
+{
+	if (cls.state != ca_connected)
+	{
+		Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
+		return;
+	}
+	
+	if (cls.demoplayback)
+		return;		// not really connected
+
+	MSG_WriteByte (&cls.message, clc_stringcmd);
+	if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0)
+	{
+		SZ_Print (&cls.message, Cmd_Argv(0));
+		SZ_Print (&cls.message, " ");
+	}
+	if (Cmd_Argc() > 1)
+		SZ_Print (&cls.message, Cmd_Args());
+	else
+		SZ_Print (&cls.message, "\n");
+}
+
+
+/*
+================
+Cmd_CheckParm
+
+Returns the position (1 to argc-1) in the command's argument list
+where the given parameter apears, or 0 if not present
+================
+*/
+
+int Cmd_CheckParm (const char *parm)
+{
+	int i;
+	
+	if (!parm)
+		Sys_Error ("Cmd_CheckParm: NULL");
+
+	for (i = 1; i < Cmd_Argc (); i++)
+		if (! Q_strcasecmp (parm, Cmd_Argv (i)))
+			return i;
+			
+	return 0;
+}
diff --git a/quake/src/WinQuake/cmd.h b/quake/src/WinQuake/cmd.h
index b2e9993..c463163 100644
--- a/quake/src/WinQuake/cmd.h
+++ b/quake/src/WinQuake/cmd.h
@@ -1,121 +1,126 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-// cmd.h -- Command buffer and command execution

-

-//===========================================================================

-

-/*

-

-Any number of commands can be added in a frame, from several different sources.

-Most commands come from either keybindings or console line input, but remote

-servers can also send across commands and entire text files can be execed.

-

-The + command line options are also added to the command buffer.

-

-The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();

-

-*/

-

-

-void Cbuf_Init (void);

-// allocates an initial text buffer that will grow as needed

-

-void Cbuf_AddText (char *text);

-// as new commands are generated from the console or keybindings,

-// the text is added to the end of the command buffer.

-

-void Cbuf_InsertText (char *text);

-// when a command wants to issue other commands immediately, the text is

-// inserted at the beginning of the buffer, before any remaining unexecuted

-// commands.

-

-void Cbuf_Execute (void);

-// Pulls off \n terminated lines of text from the command buffer and sends

-// them through Cmd_ExecuteString.  Stops when the buffer is empty.

-// Normally called once per frame, but may be explicitly invoked.

-// Do not call inside a command function!

-

-//===========================================================================

-

-/*

-

-Command execution takes a null terminated string, breaks it into tokens,

-then searches for a command or variable that matches the first token.

-

-Commands can come from three sources, but the handler functions may choose

-to dissallow the action or forward it to a remote server if the source is

-not apropriate.

-

-*/

-

-typedef void (*xcommand_t) (void);

-

-typedef enum

-{

-	src_client,		// came in over a net connection as a clc_stringcmd

-					// host_client will be valid during this state.

-	src_command		// from the command buffer

-} cmd_source_t;

-

-extern	cmd_source_t	cmd_source;

-

-void	Cmd_Init (void);

-

-void	Cmd_AddCommand (char *cmd_name, xcommand_t function);

-// called by the init functions of other parts of the program to

-// register commands and functions to call for them.

-// The cmd_name is referenced later, so it should not be in temp memory

-

-qboolean Cmd_Exists (char *cmd_name);

-// used by the cvar code to check for cvar / command name overlap

-

-char 	*Cmd_CompleteCommand (char *partial);

-// attempts to match a partial command for automatic command line completion

-// returns NULL if nothing fits

-

-int		Cmd_Argc (void);

-char	*Cmd_Argv (int arg);

-char	*Cmd_Args (void);

-// The functions that execute commands get their parameters with these

-// functions. Cmd_Argv () will return an empty string, not a NULL

-// if arg > argc, so string operations are allways safe.

-

-int Cmd_CheckParm (char *parm);

-// Returns the position (1 to argc-1) in the command's argument list

-// where the given parameter apears, or 0 if not present

-

-void Cmd_TokenizeString (char *text);

-// Takes a null terminated string.  Does not need to be /n terminated.

-// breaks the string up into arg tokens.

-

-void	Cmd_ExecuteString (char *text, cmd_source_t src);

-// Parses a single line of text into arguments and tries to execute it.

-// The text can come from the command buffer, a remote client, or stdin.

-

-void	Cmd_ForwardToServer (void);

-// adds the current command line as a clc_stringcmd to the client message.

-// things like godmode, noclip, etc, are commands directed to the server,

-// so when they are typed in at the console, they will need to be forwarded.

-

-void	Cmd_Print (char *text);

-// used by command functions to send output to either the graphics console or

-// passed as a print message to the client

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+// cmd.h -- Command buffer and command execution
+
+//===========================================================================
+
+/*
+
+Any number of commands can be added in a frame, from several different sources.
+Most commands come from either keybindings or console line input, but remote
+servers can also send across commands and entire text files can be execed.
+
+The + command line options are also added to the command buffer.
+
+The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();
+
+*/
+
+
+void Cbuf_Init (void);
+// allocates an initial text buffer that will grow as needed
+
+void Cbuf_AddText (const char *text);
+// as new commands are generated from the console or keybindings,
+// the text is added to the end of the command buffer.
+
+void Cbuf_InsertText (const char *text);
+// when a command wants to issue other commands immediately, the text is
+// inserted at the beginning of the buffer, before any remaining unexecuted
+// commands.
+
+void Cbuf_Execute (void);
+// Pulls off \n terminated lines of text from the command buffer and sends
+// them through Cmd_ExecuteString.  Stops when the buffer is empty.
+// Normally called once per frame, but may be explicitly invoked.
+// Do not call inside a command function!
+
+//===========================================================================
+
+/*
+
+Command execution takes a null terminated string, breaks it into tokens,
+then searches for a command or variable that matches the first token.
+
+Commands can come from three sources, but the handler functions may choose
+to dissallow the action or forward it to a remote server if the source is
+not apropriate.
+
+*/
+
+typedef void (*xcommand_t) (void);
+
+typedef enum
+{
+	src_client,		// came in over a net connection as a clc_stringcmd
+					// host_client will be valid during this state.
+	src_command,		// from the command buffer
+	cmd_src_t_max = 1 << 30
+} cmd_source_t;
+
+extern	cmd_source_t	cmd_source;
+
+void	Cmd_Init (void);
+
+void	Cmd_AddCommand (const char *cmd_name, xcommand_t function);
+// called by the init functions of other parts of the program to
+// register commands and functions to call for them.
+// The cmd_name is referenced later, so it should not be in temp memory
+
+qboolean Cmd_Exists (const char *cmd_name);
+// used by the cvar code to check for cvar / command name overlap
+
+const char 	*Cmd_CompleteCommand (const char *partial);
+// attempts to match a partial command for automatic command line completion
+// returns NULL if nothing fits
+
+int		Cmd_Argc (void);
+char	*Cmd_Argv (int arg);
+char	*Cmd_Args (void);
+// The functions that execute commands get their parameters with these
+// functions. Cmd_Argv () will return an empty string, not a NULL
+// if arg > argc, so string operations are allways safe.
+
+int Cmd_CheckParm (const char *parm);
+// Returns the position (1 to argc-1) in the command's argument list
+// where the given parameter apears, or 0 if not present
+
+void Cmd_TokenizeString (char *text);
+// Takes a null terminated string.  Does not need to be /n terminated.
+// breaks the string up into arg tokens.
+
+void	Cmd_ExecuteString (char *text, cmd_source_t src);
+
+// Same as Cmd_ExecuteString, but for string constants.
+void    Cmd_ExecuteString2 (const char *text, cmd_source_t src);
+
+// Parses a single line of text into arguments and tries to execute it.
+// The text can come from the command buffer, a remote client, or stdin.
+
+void	Cmd_ForwardToServer (void);
+// adds the current command line as a clc_stringcmd to the client message.
+// things like godmode, noclip, etc, are commands directed to the server,
+// so when they are typed in at the console, they will need to be forwarded.
+
+void	Cmd_Print (const char *text);
+// used by command functions to send output to either the graphics console or
+// passed as a print message to the client
+
diff --git a/quake/src/WinQuake/common.c b/quake/src/WinQuake/common.cpp
old mode 100644
new mode 100755
similarity index 86%
rename from quake/src/WinQuake/common.c
rename to quake/src/WinQuake/common.cpp
index a6f6bd9..d4ea266
--- a/quake/src/WinQuake/common.c
+++ b/quake/src/WinQuake/common.cpp
@@ -1,1827 +1,1860 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// common.c -- misc functions used in client and server

-

-#include "quakedef.h"

-

-#define NUM_SAFE_ARGVS  7

-

-static char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];

-static char     *argvdummy = " ";

-

-static char     *safeargvs[NUM_SAFE_ARGVS] =

-	{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};

-

-cvar_t  registered = {"registered","0"};

-cvar_t  cmdline = {"cmdline","0", false, true};

-

-qboolean        com_modified;   // set true if using non-id files

-

-qboolean		proghack;

-

-int             static_registered = 1;  // only for startup check, then set

-

-qboolean		msg_suppress_1 = 0;

-

-void COM_InitFilesystem (void);

-

-// if a packfile directory differs from this, it is assumed to be hacked

-#define PAK0_COUNT              339

-#define PAK0_CRC                32981

-

-char	com_token[1024];

-int		com_argc;

-char	**com_argv;

-

-#define CMDLINE_LENGTH	256

-char	com_cmdline[CMDLINE_LENGTH];

-

-qboolean		standard_quake = true, rogue, hipnotic;

-

-// this graphic needs to be in the pak file to use registered features

-unsigned short pop[] =

-{

- 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000

-,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000

-,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000

-,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600

-,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563

-,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564

-,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564

-,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563

-,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500

-,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200

-,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000

-,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000

-,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000

-,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000

-,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000

-,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000

-};

-

-/*

-

-

-All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.

-

-The "base directory" is the path to the directory holding the quake.exe and all game directories.  The sys_* files pass this to host_init in quakeparms_t->basedir.  This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory.  The base directory is

-only used during filesystem initialization.

-

-The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to.  This can be overridden with the "-game" command line parameter.  The game directory can never be changed while quake is executing.  This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.

-

-The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines.  If there is a cache directory

-specified, when a file is found by the normal search path, it will be mirrored

-into the cache directory, then opened there.

-

-

-

-FIXME:

-The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently.  This could be used to add a "-sspeed 22050" for the high quality sound edition.  Because they are added at the end, they will not override an explicit setting on the original command line.

-	

-*/

-

-//============================================================================

-

-

-// ClearLink is used for new headnodes

-void ClearLink (link_t *l)

-{

-	l->prev = l->next = l;

-}

-

-void RemoveLink (link_t *l)

-{

-	l->next->prev = l->prev;

-	l->prev->next = l->next;

-}

-

-void InsertLinkBefore (link_t *l, link_t *before)

-{

-	l->next = before;

-	l->prev = before->prev;

-	l->prev->next = l;

-	l->next->prev = l;

-}

-void InsertLinkAfter (link_t *l, link_t *after)

-{

-	l->next = after->next;

-	l->prev = after;

-	l->prev->next = l;

-	l->next->prev = l;

-}

-

-/*

-============================================================================

-

-					LIBRARY REPLACEMENT FUNCTIONS

-

-============================================================================

-*/

-

-void Q_memset (void *dest, int fill, int count)

-{

-	int             i;

-	

-	if ( (((long)dest | count) & 3) == 0)

-	{

-		count >>= 2;

-		fill = fill | (fill<<8) | (fill<<16) | (fill<<24);

-		for (i=0 ; i<count ; i++)

-			((int *)dest)[i] = fill;

-	}

-	else

-		for (i=0 ; i<count ; i++)

-			((byte *)dest)[i] = fill;

-}

-

-void Q_memcpy (void *dest, void *src, int count)

-{

-	int             i;

-	

-	if (( ( (long)dest | (long)src | count) & 3) == 0 )

-	{

-		count>>=2;

-		for (i=0 ; i<count ; i++)

-			((int *)dest)[i] = ((int *)src)[i];

-	}

-	else

-		for (i=0 ; i<count ; i++)

-			((byte *)dest)[i] = ((byte *)src)[i];

-}

-

-int Q_memcmp (void *m1, void *m2, int count)

-{

-	while(count)

-	{

-		count--;

-		if (((byte *)m1)[count] != ((byte *)m2)[count])

-			return -1;

-	}

-	return 0;

-}

-

-void Q_strcpy (char *dest, char *src)

-{

-	while (*src)

-	{

-		*dest++ = *src++;

-	}

-	*dest++ = 0;

-}

-

-void Q_strncpy (char *dest, char *src, int count)

-{

-	while (*src && count--)

-	{

-		*dest++ = *src++;

-	}

-	if (count)

-		*dest++ = 0;

-}

-

-int Q_strlen (char *str)

-{

-	int             count;

-	

-	count = 0;

-	while (str[count])

-		count++;

-

-	return count;

-}

-

-char *Q_strrchr(char *s, char c)

-{

-    int len = Q_strlen(s);

-    s += len;

-    while (len--)

-	if (*--s == c) return s;

-    return 0;

-}

-

-void Q_strcat (char *dest, char *src)

-{

-	dest += Q_strlen(dest);

-	Q_strcpy (dest, src);

-}

-

-int Q_strcmp (char *s1, char *s2)

-{

-	while (1)

-	{

-		if (*s1 != *s2)

-			return -1;              // strings not equal    

-		if (!*s1)

-			return 0;               // strings are equal

-		s1++;

-		s2++;

-	}

-	

-	return -1;

-}

-

-int Q_strncmp (char *s1, char *s2, int count)

-{

-	while (1)

-	{

-		if (!count--)

-			return 0;

-		if (*s1 != *s2)

-			return -1;              // strings not equal    

-		if (!*s1)

-			return 0;               // strings are equal

-		s1++;

-		s2++;

-	}

-	

-	return -1;

-}

-

-int Q_strncasecmp (char *s1, char *s2, int n)

-{

-	int             c1, c2;

-	

-	while (1)

-	{

-		c1 = *s1++;

-		c2 = *s2++;

-

-		if (!n--)

-			return 0;               // strings are equal until end point

-		

-		if (c1 != c2)

-		{

-			if (c1 >= 'a' && c1 <= 'z')

-				c1 -= ('a' - 'A');

-			if (c2 >= 'a' && c2 <= 'z')

-				c2 -= ('a' - 'A');

-			if (c1 != c2)

-				return -1;              // strings not equal

-		}

-		if (!c1)

-			return 0;               // strings are equal

-//              s1++;

-//              s2++;

-	}

-	

-	return -1;

-}

-

-int Q_strcasecmp (char *s1, char *s2)

-{

-	return Q_strncasecmp (s1, s2, 99999);

-}

-

-int Q_atoi (char *str)

-{

-	int             val;

-	int             sign;

-	int             c;

-	

-	if (*str == '-')

-	{

-		sign = -1;

-		str++;

-	}

-	else

-		sign = 1;

-		

-	val = 0;

-

-//

-// check for hex

-//

-	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )

-	{

-		str += 2;

-		while (1)

-		{

-			c = *str++;

-			if (c >= '0' && c <= '9')

-				val = (val<<4) + c - '0';

-			else if (c >= 'a' && c <= 'f')

-				val = (val<<4) + c - 'a' + 10;

-			else if (c >= 'A' && c <= 'F')

-				val = (val<<4) + c - 'A' + 10;

-			else

-				return val*sign;

-		}

-	}

-	

-//

-// check for character

-//

-	if (str[0] == '\'')

-	{

-		return sign * str[1];

-	}

-	

-//

-// assume decimal

-//

-	while (1)

-	{

-		c = *str++;

-		if (c <'0' || c > '9')

-			return val*sign;

-		val = val*10 + c - '0';

-	}

-	

-	return 0;

-}

-

-

-float Q_atof (char *str)

-{

-	double			val;

-	int             sign;

-	int             c;

-	int             decimal, total;

-	

-	if (*str == '-')

-	{

-		sign = -1;

-		str++;

-	}

-	else

-		sign = 1;

-		

-	val = 0;

-

-//

-// check for hex

-//

-	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )

-	{

-		str += 2;

-		while (1)

-		{

-			c = *str++;

-			if (c >= '0' && c <= '9')

-				val = (val*16) + c - '0';

-			else if (c >= 'a' && c <= 'f')

-				val = (val*16) + c - 'a' + 10;

-			else if (c >= 'A' && c <= 'F')

-				val = (val*16) + c - 'A' + 10;

-			else

-				return val*sign;

-		}

-	}

-	

-//

-// check for character

-//

-	if (str[0] == '\'')

-	{

-		return sign * str[1];

-	}

-	

-//

-// assume decimal

-//

-	decimal = -1;

-	total = 0;

-	while (1)

-	{

-		c = *str++;

-		if (c == '.')

-		{

-			decimal = total;

-			continue;

-		}

-		if (c <'0' || c > '9')

-			break;

-		val = val*10 + c - '0';

-		total++;

-	}

-

-	if (decimal == -1)

-		return val*sign;

-	while (total > decimal)

-	{

-		val /= 10;

-		total--;

-	}

-	

-	return val*sign;

-}

-

-/*

-============================================================================

-

-					BYTE ORDER FUNCTIONS

-

-============================================================================

-*/

-

-qboolean        bigendien;

-

-short   (*BigShort) (short l);

-short   (*LittleShort) (short l);

-int     (*BigLong) (int l);

-int     (*LittleLong) (int l);

-float   (*BigFloat) (float l);

-float   (*LittleFloat) (float l);

-

-short   ShortSwap (short l)

-{

-	byte    b1,b2;

-

-	b1 = l&255;

-	b2 = (l>>8)&255;

-

-	return (b1<<8) + b2;

-}

-

-short   ShortNoSwap (short l)

-{

-	return l;

-}

-

-int    LongSwap (int l)

-{

-	byte    b1,b2,b3,b4;

-

-	b1 = l&255;

-	b2 = (l>>8)&255;

-	b3 = (l>>16)&255;

-	b4 = (l>>24)&255;

-

-	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;

-}

-

-int     LongNoSwap (int l)

-{

-	return l;

-}

-

-float FloatSwap (float f)

-{

-	union

-	{

-		float   f;

-		byte    b[4];

-	} dat1, dat2;

-	

-	

-	dat1.f = f;

-	dat2.b[0] = dat1.b[3];

-	dat2.b[1] = dat1.b[2];

-	dat2.b[2] = dat1.b[1];

-	dat2.b[3] = dat1.b[0];

-	return dat2.f;

-}

-

-float FloatNoSwap (float f)

-{

-	return f;

-}

-

-/*

-==============================================================================

-

-			MESSAGE IO FUNCTIONS

-

-Handles byte ordering and avoids alignment errors

-==============================================================================

-*/

-

-//

-// writing functions

-//

-

-void MSG_WriteChar (sizebuf_t *sb, int c)

-{

-	byte    *buf;

-	

-#ifdef PARANOID

-	if (c < -128 || c > 127)

-		Sys_Error ("MSG_WriteChar: range error");

-#endif

-

-	buf = SZ_GetSpace (sb, 1);

-	buf[0] = c;

-}

-

-void MSG_WriteByte (sizebuf_t *sb, int c)

-{

-	byte    *buf;

-	

-#ifdef PARANOID

-	if (c < 0 || c > 255)

-		Sys_Error ("MSG_WriteByte: range error");

-#endif

-

-	buf = SZ_GetSpace (sb, 1);

-	buf[0] = c;

-}

-

-void MSG_WriteShort (sizebuf_t *sb, int c)

-{

-	byte    *buf;

-	

-#ifdef PARANOID

-	if (c < ((short)0x8000) || c > (short)0x7fff)

-		Sys_Error ("MSG_WriteShort: range error");

-#endif

-

-	buf = SZ_GetSpace (sb, 2);

-	buf[0] = c&0xff;

-	buf[1] = c>>8;

-}

-

-void MSG_WriteLong (sizebuf_t *sb, int c)

-{

-	byte    *buf;

-	

-	buf = SZ_GetSpace (sb, 4);

-	buf[0] = c&0xff;

-	buf[1] = (c>>8)&0xff;

-	buf[2] = (c>>16)&0xff;

-	buf[3] = c>>24;

-}

-

-void MSG_WriteFloat (sizebuf_t *sb, float f)

-{

-	union

-	{

-		float   f;

-		int     l;

-	} dat;

-	

-	

-	dat.f = f;

-	dat.l = LittleLong (dat.l);

-	

-	SZ_Write (sb, &dat.l, 4);

-}

-

-void MSG_WriteString (sizebuf_t *sb, char *s)

-{

-	if (!s)

-		SZ_Write (sb, "", 1);

-	else

-		SZ_Write (sb, s, Q_strlen(s)+1);

-}

-

-void MSG_WriteCoord (sizebuf_t *sb, float f)

-{

-	MSG_WriteShort (sb, (int)(f*8));

-}

-

-void MSG_WriteAngle (sizebuf_t *sb, float f)

-{

-	MSG_WriteByte (sb, ((int)f*256/360) & 255);

-}

-

-//

-// reading functions

-//

-int                     msg_readcount;

-qboolean        msg_badread;

-

-void MSG_BeginReading (void)

-{

-	msg_readcount = 0;

-	msg_badread = false;

-}

-

-// returns -1 and sets msg_badread if no more characters are available

-int MSG_ReadChar (void)

-{

-	int     c;

-	

-	if (msg_readcount+1 > net_message.cursize)

-	{

-		msg_badread = true;

-		return -1;

-	}

-		

-	c = (signed char)net_message.data[msg_readcount];

-	msg_readcount++;

-	

-	return c;

-}

-

-int MSG_ReadByte (void)

-{

-	int     c;

-	

-	if (msg_readcount+1 > net_message.cursize)

-	{

-		msg_badread = true;

-		return -1;

-	}

-		

-	c = (unsigned char)net_message.data[msg_readcount];

-	msg_readcount++;

-	

-	return c;

-}

-

-int MSG_ReadShort (void)

-{

-	int     c;

-	

-	if (msg_readcount+2 > net_message.cursize)

-	{

-		msg_badread = true;

-		return -1;

-	}

-		

-	c = (short)(net_message.data[msg_readcount]

-	+ (net_message.data[msg_readcount+1]<<8));

-	

-	msg_readcount += 2;

-	

-	return c;

-}

-

-int MSG_ReadLong (void)

-{

-	int     c;

-	

-	if (msg_readcount+4 > net_message.cursize)

-	{

-		msg_badread = true;

-		return -1;

-	}

-		

-	c = net_message.data[msg_readcount]

-	+ (net_message.data[msg_readcount+1]<<8)

-	+ (net_message.data[msg_readcount+2]<<16)

-	+ (net_message.data[msg_readcount+3]<<24);

-	

-	msg_readcount += 4;

-	

-	return c;

-}

-

-float MSG_ReadFloat (void)

-{

-	union

-	{

-		byte    b[4];

-		float   f;

-		int     l;

-	} dat;

-	

-	dat.b[0] =      net_message.data[msg_readcount];

-	dat.b[1] =      net_message.data[msg_readcount+1];

-	dat.b[2] =      net_message.data[msg_readcount+2];

-	dat.b[3] =      net_message.data[msg_readcount+3];

-	msg_readcount += 4;

-	

-	dat.l = LittleLong (dat.l);

-

-	return dat.f;   

-}

-

-char *MSG_ReadString (void)

-{

-	static char     string[2048];

-	int             l,c;

-	

-	l = 0;

-	do

-	{

-		c = MSG_ReadChar ();

-		if (c == -1 || c == 0)

-			break;

-		string[l] = c;

-		l++;

-	} while (l < sizeof(string)-1);

-	

-	string[l] = 0;

-	

-	return string;

-}

-

-float MSG_ReadCoord (void)

-{

-	return MSG_ReadShort() * (1.0/8);

-}

-

-float MSG_ReadAngle (void)

-{

-	return MSG_ReadChar() * (360.0/256);

-}

-

-

-

-//===========================================================================

-

-void SZ_Alloc (sizebuf_t *buf, int startsize)

-{

-	if (startsize < 256)

-		startsize = 256;

-	buf->data = Hunk_AllocName (startsize, "sizebuf");

-	buf->maxsize = startsize;

-	buf->cursize = 0;

-}

-

-

-void SZ_Free (sizebuf_t *buf)

-{

-//      Z_Free (buf->data);

-//      buf->data = NULL;

-//      buf->maxsize = 0;

-	buf->cursize = 0;

-}

-

-void SZ_Clear (sizebuf_t *buf)

-{

-	buf->cursize = 0;

-}

-

-void *SZ_GetSpace (sizebuf_t *buf, int length)

-{

-	void    *data;

-	

-	if (buf->cursize + length > buf->maxsize)

-	{

-		if (!buf->allowoverflow)

-			Sys_Error ("SZ_GetSpace: overflow without allowoverflow set");

-		

-		if (length > buf->maxsize)

-			Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);

-			

-		buf->overflowed = true;

-		Con_Printf ("SZ_GetSpace: overflow");

-		SZ_Clear (buf); 

-	}

-

-	data = buf->data + buf->cursize;

-	buf->cursize += length;

-	

-	return data;

-}

-

-void SZ_Write (sizebuf_t *buf, void *data, int length)

-{

-	Q_memcpy (SZ_GetSpace(buf,length),data,length);         

-}

-

-void SZ_Print (sizebuf_t *buf, char *data)

-{

-	int             len;

-	

-	len = Q_strlen(data)+1;

-

-// byte * cast to keep VC++ happy

-	if (buf->data[buf->cursize-1])

-		Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0

-	else

-		Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0

-}

-

-

-//============================================================================

-

-

-/*

-============

-COM_SkipPath

-============

-*/

-char *COM_SkipPath (char *pathname)

-{

-	char    *last;

-	

-	last = pathname;

-	while (*pathname)

-	{

-		if (*pathname=='/')

-			last = pathname+1;

-		pathname++;

-	}

-	return last;

-}

-

-/*

-============

-COM_StripExtension

-============

-*/

-void COM_StripExtension (char *in, char *out)

-{

-	while (*in && *in != '.')

-		*out++ = *in++;

-	*out = 0;

-}

-

-/*

-============

-COM_FileExtension

-============

-*/

-char *COM_FileExtension (char *in)

-{

-	static char exten[8];

-	int             i;

-

-	while (*in && *in != '.')

-		in++;

-	if (!*in)

-		return "";

-	in++;

-	for (i=0 ; i<7 && *in ; i++,in++)

-		exten[i] = *in;

-	exten[i] = 0;

-	return exten;

-}

-

-/*

-============

-COM_FileBase

-============

-*/

-void COM_FileBase (char *in, char *out)

-{

-	char *s, *s2;

-	

-	s = in + strlen(in) - 1;

-	

-	while (s != in && *s != '.')

-		s--;

-	

-	for (s2 = s ; *s2 && *s2 != '/' ; s2--)

-	;

-	

-	if (s-s2 < 2)

-		strcpy (out,"?model?");

-	else

-	{

-		s--;

-		strncpy (out,s2+1, s-s2);

-		out[s-s2] = 0;

-	}

-}

-

-

-/*

-==================

-COM_DefaultExtension

-==================

-*/

-void COM_DefaultExtension (char *path, char *extension)

-{

-	char    *src;

-//

-// if path doesn't have a .EXT, append extension

-// (extension should include the .)

-//

-	src = path + strlen(path) - 1;

-

-	while (*src != '/' && src != path)

-	{

-		if (*src == '.')

-			return;                 // it has an extension

-		src--;

-	}

-

-	strcat (path, extension);

-}

-

-

-/*

-==============

-COM_Parse

-

-Parse a token out of a string

-==============

-*/

-char *COM_Parse (char *data)

-{

-	int             c;

-	int             len;

-	

-	len = 0;

-	com_token[0] = 0;

-	

-	if (!data)

-		return NULL;

-		

-// skip whitespace

-skipwhite:

-	while ( (c = *data) <= ' ')

-	{

-		if (c == 0)

-			return NULL;                    // end of file;

-		data++;

-	}

-	

-// skip // comments

-	if (c=='/' && data[1] == '/')

-	{

-		while (*data && *data != '\n')

-			data++;

-		goto skipwhite;

-	}

-	

-

-// handle quoted strings specially

-	if (c == '\"')

-	{

-		data++;

-		while (1)

-		{

-			c = *data++;

-			if (c=='\"' || !c)

-			{

-				com_token[len] = 0;

-				return data;

-			}

-			com_token[len] = c;

-			len++;

-		}

-	}

-

-// parse single characters

-	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')

-	{

-		com_token[len] = c;

-		len++;

-		com_token[len] = 0;

-		return data+1;

-	}

-

-// parse a regular word

-	do

-	{

-		com_token[len] = c;

-		data++;

-		len++;

-		c = *data;

-	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')

-			break;

-	} while (c>32);

-	

-	com_token[len] = 0;

-	return data;

-}

-

-

-/*

-================

-COM_CheckParm

-

-Returns the position (1 to argc-1) in the program's argument list

-where the given parameter apears, or 0 if not present

-================

-*/

-int COM_CheckParm (char *parm)

-{

-	int             i;

-	

-	for (i=1 ; i<com_argc ; i++)

-	{

-		if (!com_argv[i])

-			continue;               // NEXTSTEP sometimes clears appkit vars.

-		if (!Q_strcmp (parm,com_argv[i]))

-			return i;

-	}

-		

-	return 0;

-}

-

-/*

-================

-COM_CheckRegistered

-

-Looks for the pop.txt file and verifies it.

-Sets the "registered" cvar.

-Immediately exits out if an alternate game was attempted to be started without

-being registered.

-================

-*/

-void COM_CheckRegistered (void)

-{

-	int             h;

-	unsigned short  check[128];

-	int                     i;

-

-	COM_OpenFile("gfx/pop.lmp", &h);

-	static_registered = 0;

-

-	if (h == -1)

-	{

-#if WINDED

-	Sys_Error ("This dedicated server requires a full registered copy of Quake");

-#endif

-		Con_Printf ("Playing shareware version.\n");

-		if (com_modified)

-			Sys_Error ("You must have the registered version to use modified games");

-		return;

-	}

-

-	Sys_FileRead (h, check, sizeof(check));

-	COM_CloseFile (h);

-	

-	for (i=0 ; i<128 ; i++)

-		if (pop[i] != (unsigned short)BigShort (check[i]))

-			Sys_Error ("Corrupted data file.");

-	

-	Cvar_Set ("cmdline", com_cmdline);

-	Cvar_Set ("registered", "1");

-	static_registered = 1;

-	Con_Printf ("Playing registered version.\n");

-}

-

-

-void COM_Path_f (void);

-

-

-/*

-================

-COM_InitArgv

-================

-*/

-void COM_InitArgv (int argc, char **argv)

-{

-	qboolean        safe;

-	int             i, j, n;

-

-// reconstitute the command line for the cmdline externally visible cvar

-	n = 0;

-

-	for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)

-	{

-		i = 0;

-

-		while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])

-		{

-			com_cmdline[n++] = argv[j][i++];

-		}

-

-		if (n < (CMDLINE_LENGTH - 1))

-			com_cmdline[n++] = ' ';

-		else

-			break;

-	}

-

-	com_cmdline[n] = 0;

-

-	safe = false;

-

-	for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;

-		 com_argc++)

-	{

-		largv[com_argc] = argv[com_argc];

-		if (!Q_strcmp ("-safe", argv[com_argc]))

-			safe = true;

-	}

-

-	if (safe)

-	{

-	// force all the safe-mode switches. Note that we reserved extra space in

-	// case we need to add these, so we don't need an overflow check

-		for (i=0 ; i<NUM_SAFE_ARGVS ; i++)

-		{

-			largv[com_argc] = safeargvs[i];

-			com_argc++;

-		}

-	}

-

-	largv[com_argc] = argvdummy;

-	com_argv = largv;

-

-	if (COM_CheckParm ("-rogue"))

-	{

-		rogue = true;

-		standard_quake = false;

-	}

-

-	if (COM_CheckParm ("-hipnotic"))

-	{

-		hipnotic = true;

-		standard_quake = false;

-	}

-}

-

-

-/*

-================

-COM_Init

-================

-*/

-void COM_Init (char *basedir)

-{

-	byte    swaptest[2] = {1,0};

-

-// set the byte swapping variables in a portable manner 

-	if ( *(short *)swaptest == 1)

-	{

-		bigendien = false;

-		BigShort = ShortSwap;

-		LittleShort = ShortNoSwap;

-		BigLong = LongSwap;

-		LittleLong = LongNoSwap;

-		BigFloat = FloatSwap;

-		LittleFloat = FloatNoSwap;

-	}

-	else

-	{

-		bigendien = true;

-		BigShort = ShortNoSwap;

-		LittleShort = ShortSwap;

-		BigLong = LongNoSwap;

-		LittleLong = LongSwap;

-		BigFloat = FloatNoSwap;

-		LittleFloat = FloatSwap;

-	}

-

-	Cvar_RegisterVariable (&registered);

-	Cvar_RegisterVariable (&cmdline);

-	Cmd_AddCommand ("path", COM_Path_f);

-

-	COM_InitFilesystem ();

-	COM_CheckRegistered ();

-}

-

-

-/*

-============

-va

-

-does a varargs printf into a temp buffer, so I don't need to have

-varargs versions of all text functions.

-FIXME: make this buffer size safe someday

-============

-*/

-char    *va(char *format, ...)

-{

-	va_list         argptr;

-	static char             string[1024];

-	

-	va_start (argptr, format);

-	vsprintf (string, format,argptr);

-	va_end (argptr);

-

-	return string;  

-}

-

-

-/// just for debugging

-int     memsearch (byte *start, int count, int search)

-{

-	int             i;

-	

-	for (i=0 ; i<count ; i++)

-		if (start[i] == search)

-			return i;

-	return -1;

-}

-

-/*

-=============================================================================

-

-QUAKE FILESYSTEM

-

-=============================================================================

-*/

-

-int     com_filesize;

-

-

-//

-// in memory

-//

-

-typedef struct

-{

-	char    name[MAX_QPATH];

-	int             filepos, filelen;

-} packfile_t;

-

-typedef struct pack_s

-{

-	char    filename[MAX_OSPATH];

-	int             handle;

-	int             numfiles;

-	packfile_t      *files;

-} pack_t;

-

-//

-// on disk

-//

-typedef struct

-{

-	char    name[56];

-	int             filepos, filelen;

-} dpackfile_t;

-

-typedef struct

-{

-	char    id[4];

-	int             dirofs;

-	int             dirlen;

-} dpackheader_t;

-

-#define MAX_FILES_IN_PACK       2048

-

-char    com_cachedir[MAX_OSPATH];

-char    com_gamedir[MAX_OSPATH];

-

-typedef struct searchpath_s

-{

-	char    filename[MAX_OSPATH];

-	pack_t  *pack;          // only one of filename / pack will be used

-	struct searchpath_s *next;

-} searchpath_t;

-

-searchpath_t    *com_searchpaths;

-

-/*

-============

-COM_Path_f

-

-============

-*/

-void COM_Path_f (void)

-{

-	searchpath_t    *s;

-	

-	Con_Printf ("Current search path:\n");

-	for (s=com_searchpaths ; s ; s=s->next)

-	{

-		if (s->pack)

-		{

-			Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);

-		}

-		else

-			Con_Printf ("%s\n", s->filename);

-	}

-}

-

-/*

-============

-COM_WriteFile

-

-The filename will be prefixed by the current game directory

-============

-*/

-void COM_WriteFile (char *filename, void *data, int len)

-{

-	int             handle;

-	char    name[MAX_OSPATH];

-	

-	sprintf (name, "%s/%s", com_gamedir, filename);

-

-	handle = Sys_FileOpenWrite (name);

-	if (handle == -1)

-	{

-		Sys_Printf ("COM_WriteFile: failed on %s\n", name);

-		return;

-	}

-	

-	Sys_Printf ("COM_WriteFile: %s\n", name);

-	Sys_FileWrite (handle, data, len);

-	Sys_FileClose (handle);

-}

-

-

-/*

-============

-COM_CreatePath

-

-Only used for CopyFile

-============

-*/

-void    COM_CreatePath (char *path)

-{

-	char    *ofs;

-	

-	for (ofs = path+1 ; *ofs ; ofs++)

-	{

-		if (*ofs == '/')

-		{       // create the directory

-			*ofs = 0;

-			Sys_mkdir (path);

-			*ofs = '/';

-		}

-	}

-}

-

-

-/*

-===========

-COM_CopyFile

-

-Copies a file over from the net to the local cache, creating any directories

-needed.  This is for the convenience of developers using ISDN from home.

-===========

-*/

-void COM_CopyFile (char *netpath, char *cachepath)

-{

-	int             in, out;

-	int             remaining, count;

-	char    buf[4096];

-	

-	remaining = Sys_FileOpenRead (netpath, &in);            

-	COM_CreatePath (cachepath);     // create directories up to the cache file

-	out = Sys_FileOpenWrite (cachepath);

-	

-	while (remaining)

-	{

-		if (remaining < sizeof(buf))

-			count = remaining;

-		else

-			count = sizeof(buf);

-		Sys_FileRead (in, buf, count);

-		Sys_FileWrite (out, buf, count);

-		remaining -= count;

-	}

-

-	Sys_FileClose (in);

-	Sys_FileClose (out);    

-}

-

-/*

-===========

-COM_FindFile

-

-Finds the file in the search path.

-Sets com_filesize and one of handle or file

-===========

-*/

-int COM_FindFile (char *filename, int *handle, FILE **file)

-{

-	searchpath_t    *search;

-	char            netpath[MAX_OSPATH];

-	char            cachepath[MAX_OSPATH];

-	pack_t          *pak;

-	int                     i;

-	int                     findtime, cachetime;

-

-	if (file && handle)

-		Sys_Error ("COM_FindFile: both handle and file set");

-	if (!file && !handle)

-		Sys_Error ("COM_FindFile: neither handle or file set");

-		

-//

-// search through the path, one element at a time

-//

-	search = com_searchpaths;

-	if (proghack)

-	{	// gross hack to use quake 1 progs with quake 2 maps

-		if (!strcmp(filename, "progs.dat"))

-			search = search->next;

-	}

-

-	for ( ; search ; search = search->next)

-	{

-	// is the element a pak file?

-		if (search->pack)

-		{

-		// look through all the pak file elements

-			pak = search->pack;

-			for (i=0 ; i<pak->numfiles ; i++)

-				if (!strcmp (pak->files[i].name, filename))

-				{       // found it!

-					Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);

-					if (handle)

-					{

-						*handle = pak->handle;

-						Sys_FileSeek (pak->handle, pak->files[i].filepos);

-					}

-					else

-					{       // open a new file on the pakfile

-						*file = fopen (pak->filename, "rb");

-						if (*file)

-							fseek (*file, pak->files[i].filepos, SEEK_SET);

-					}

-					com_filesize = pak->files[i].filelen;

-					return com_filesize;

-				}

-		}

-		else

-		{               

-	// check a file in the directory tree

-			if (!static_registered)

-			{       // if not a registered version, don't ever go beyond base

-				if ( strchr (filename, '/') || strchr (filename,'\\'))

-					continue;

-			}

-			

-			sprintf (netpath, "%s/%s",search->filename, filename);

-			

-			findtime = Sys_FileTime (netpath);

-			if (findtime == -1)

-				continue;

-				

-		// see if the file needs to be updated in the cache

-			if (!com_cachedir[0])

-				strcpy (cachepath, netpath);

-			else

-			{	

-#if defined(_WIN32)

-				if ((strlen(netpath) < 2) || (netpath[1] != ':'))

-					sprintf (cachepath,"%s%s", com_cachedir, netpath);

-				else

-					sprintf (cachepath,"%s%s", com_cachedir, netpath+2);

-#else

-				sprintf (cachepath,"%s%s", com_cachedir, netpath);

-#endif

-

-				cachetime = Sys_FileTime (cachepath);

-			

-				if (cachetime < findtime)

-					COM_CopyFile (netpath, cachepath);

-				strcpy (netpath, cachepath);

-			}	

-

-			Sys_Printf ("FindFile: %s\n",netpath);

-			com_filesize = Sys_FileOpenRead (netpath, &i);

-			if (handle)

-				*handle = i;

-			else

-			{

-				Sys_FileClose (i);

-				*file = fopen (netpath, "rb");

-			}

-			return com_filesize;

-		}

-		

-	}

-	

-	Sys_Printf ("FindFile: can't find %s\n", filename);

-	

-	if (handle)

-		*handle = -1;

-	else

-		*file = NULL;

-	com_filesize = -1;

-	return -1;

-}

-

-

-/*

-===========

-COM_OpenFile

-

-filename never has a leading slash, but may contain directory walks

-returns a handle and a length

-it may actually be inside a pak file

-===========

-*/

-int COM_OpenFile (char *filename, int *handle)

-{

-	return COM_FindFile (filename, handle, NULL);

-}

-

-/*

-===========

-COM_FOpenFile

-

-If the requested file is inside a packfile, a new FILE * will be opened

-into the file.

-===========

-*/

-int COM_FOpenFile (char *filename, FILE **file)

-{

-	return COM_FindFile (filename, NULL, file);

-}

-

-/*

-============

-COM_CloseFile

-

-If it is a pak file handle, don't really close it

-============

-*/

-void COM_CloseFile (int h)

-{

-	searchpath_t    *s;

-	

-	for (s = com_searchpaths ; s ; s=s->next)

-		if (s->pack && s->pack->handle == h)

-			return;

-			

-	Sys_FileClose (h);

-}

-

-

-/*

-============

-COM_LoadFile

-

-Filename are reletive to the quake directory.

-Allways appends a 0 byte.

-============

-*/

-cache_user_t *loadcache;

-byte    *loadbuf;

-int             loadsize;

-byte *COM_LoadFile (char *path, int usehunk)

-{

-	int             h;

-	byte    *buf;

-	char    base[32];

-	int             len;

-

-	buf = NULL;     // quiet compiler warning

-

-// look for it in the filesystem or pack files

-	len = COM_OpenFile (path, &h);

-	if (h == -1)

-		return NULL;

-	

-// extract the filename base name for hunk tag

-	COM_FileBase (path, base);

-	

-	if (usehunk == 1)

-		buf = Hunk_AllocName (len+1, base);

-	else if (usehunk == 2)

-		buf = Hunk_TempAlloc (len+1);

-	else if (usehunk == 0)

-		buf = Z_Malloc (len+1);

-	else if (usehunk == 3)

-		buf = Cache_Alloc (loadcache, len+1, base);

-	else if (usehunk == 4)

-	{

-		if (len+1 > loadsize)

-			buf = Hunk_TempAlloc (len+1);

-		else

-			buf = loadbuf;

-	}

-	else

-		Sys_Error ("COM_LoadFile: bad usehunk");

-

-	if (!buf)

-		Sys_Error ("COM_LoadFile: not enough space for %s", path);

-		

-	((byte *)buf)[len] = 0;

-

-	Draw_BeginDisc ();

-	Sys_FileRead (h, buf, len);                     

-	COM_CloseFile (h);

-	Draw_EndDisc ();

-

-	return buf;

-}

-

-byte *COM_LoadHunkFile (char *path)

-{

-	return COM_LoadFile (path, 1);

-}

-

-byte *COM_LoadTempFile (char *path)

-{

-	return COM_LoadFile (path, 2);

-}

-

-void COM_LoadCacheFile (char *path, struct cache_user_s *cu)

-{

-	loadcache = cu;

-	COM_LoadFile (path, 3);

-}

-

-// uses temp hunk if larger than bufsize

-byte *COM_LoadStackFile (char *path, void *buffer, int bufsize)

-{

-	byte    *buf;

-	

-	loadbuf = (byte *)buffer;

-	loadsize = bufsize;

-	buf = COM_LoadFile (path, 4);

-	

-	return buf;

-}

-

-/*

-=================

-COM_LoadPackFile

-

-Takes an explicit (not game tree related) path to a pak file.

-

-Loads the header and directory, adding the files at the beginning

-of the list so they override previous pack files.

-=================

-*/

-pack_t *COM_LoadPackFile (char *packfile)

-{

-	dpackheader_t   header;

-	int                             i;

-	packfile_t              *newfiles;

-	int                             numpackfiles;

-	pack_t                  *pack;

-	int                             packhandle;

-	dpackfile_t             info[MAX_FILES_IN_PACK];

-	unsigned short          crc;

-

-	if (Sys_FileOpenRead (packfile, &packhandle) == -1)

-	{

-//              Con_Printf ("Couldn't open %s\n", packfile);

-		return NULL;

-	}

-	Sys_FileRead (packhandle, (void *)&header, sizeof(header));

-	if (header.id[0] != 'P' || header.id[1] != 'A'

-	|| header.id[2] != 'C' || header.id[3] != 'K')

-		Sys_Error ("%s is not a packfile", packfile);

-	header.dirofs = LittleLong (header.dirofs);

-	header.dirlen = LittleLong (header.dirlen);

-

-	numpackfiles = header.dirlen / sizeof(dpackfile_t);

-

-	if (numpackfiles > MAX_FILES_IN_PACK)

-		Sys_Error ("%s has %i files", packfile, numpackfiles);

-

-	if (numpackfiles != PAK0_COUNT)

-		com_modified = true;    // not the original file

-

-	newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile");

-

-	Sys_FileSeek (packhandle, header.dirofs);

-	Sys_FileRead (packhandle, (void *)info, header.dirlen);

-

-// crc the directory to check for modifications

-	CRC_Init (&crc);

-	for (i=0 ; i<header.dirlen ; i++)

-		CRC_ProcessByte (&crc, ((byte *)info)[i]);

-	if (crc != PAK0_CRC)

-		com_modified = true;

-

-// parse the directory

-	for (i=0 ; i<numpackfiles ; i++)

-	{

-		strcpy (newfiles[i].name, info[i].name);

-		newfiles[i].filepos = LittleLong(info[i].filepos);

-		newfiles[i].filelen = LittleLong(info[i].filelen);

-	}

-

-	pack = Hunk_Alloc (sizeof (pack_t));

-	strcpy (pack->filename, packfile);

-	pack->handle = packhandle;

-	pack->numfiles = numpackfiles;

-	pack->files = newfiles;

-	

-	Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);

-	return pack;

-}

-

-

-/*

-================

-COM_AddGameDirectory

-

-Sets com_gamedir, adds the directory to the head of the path,

-then loads and adds pak1.pak pak2.pak ... 

-================

-*/

-void COM_AddGameDirectory (char *dir)

-{

-	int                             i;

-	searchpath_t    *search;

-	pack_t                  *pak;

-	char                    pakfile[MAX_OSPATH];

-

-	strcpy (com_gamedir, dir);

-

-//

-// add the directory to the search path

-//

-	search = Hunk_Alloc (sizeof(searchpath_t));

-	strcpy (search->filename, dir);

-	search->next = com_searchpaths;

-	com_searchpaths = search;

-

-//

-// add any pak files in the format pak0.pak pak1.pak, ...

-//

-	for (i=0 ; ; i++)

-	{

-		sprintf (pakfile, "%s/pak%i.pak", dir, i);

-		pak = COM_LoadPackFile (pakfile);

-		if (!pak)

-			break;

-		search = Hunk_Alloc (sizeof(searchpath_t));

-		search->pack = pak;

-		search->next = com_searchpaths;

-		com_searchpaths = search;               

-	}

-

-//

-// add the contents of the parms.txt file to the end of the command line

-//

-

-}

-

-/*

-================

-COM_InitFilesystem

-================

-*/

-void COM_InitFilesystem (void)

-{

-	int             i, j;

-	char    basedir[MAX_OSPATH];

-	searchpath_t    *search;

-

-//

-// -basedir <path>

-// Overrides the system supplied base directory (under GAMENAME)

-//

-	i = COM_CheckParm ("-basedir");

-	if (i && i < com_argc-1)

-		strcpy (basedir, com_argv[i+1]);

-	else

-		strcpy (basedir, host_parms.basedir);

-

-	j = strlen (basedir);

-

-	if (j > 0)

-	{

-		if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))

-			basedir[j-1] = 0;

-	}

-

-//

-// -cachedir <path>

-// Overrides the system supplied cache directory (NULL or /qcache)

-// -cachedir - will disable caching.

-//

-	i = COM_CheckParm ("-cachedir");

-	if (i && i < com_argc-1)

-	{

-		if (com_argv[i+1][0] == '-')

-			com_cachedir[0] = 0;

-		else

-			strcpy (com_cachedir, com_argv[i+1]);

-	}

-	else if (host_parms.cachedir)

-		strcpy (com_cachedir, host_parms.cachedir);

-	else

-		com_cachedir[0] = 0;

-

-//

-// start up with GAMENAME by default (id1)

-//

-	COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );

-

-	if (COM_CheckParm ("-rogue"))

-		COM_AddGameDirectory (va("%s/rogue", basedir) );

-	if (COM_CheckParm ("-hipnotic"))

-		COM_AddGameDirectory (va("%s/hipnotic", basedir) );

-

-//

-// -game <gamedir>

-// Adds basedir/gamedir as an override game

-//

-	i = COM_CheckParm ("-game");

-	if (i && i < com_argc-1)

-	{

-		com_modified = true;

-		COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));

-	}

-

-//

-// -path <dir or packfile> [<dir or packfile>] ...

-// Fully specifies the exact serach path, overriding the generated one

-//

-	i = COM_CheckParm ("-path");

-	if (i)

-	{

-		com_modified = true;

-		com_searchpaths = NULL;

-		while (++i < com_argc)

-		{

-			if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')

-				break;

-			

-			search = Hunk_Alloc (sizeof(searchpath_t));

-			if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )

-			{

-				search->pack = COM_LoadPackFile (com_argv[i]);

-				if (!search->pack)

-					Sys_Error ("Couldn't load packfile: %s", com_argv[i]);

-			}

-			else

-				strcpy (search->filename, com_argv[i]);

-			search->next = com_searchpaths;

-			com_searchpaths = search;

-		}

-	}

-

-	if (COM_CheckParm ("-proghack"))

-		proghack = true;

-}

-

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// common.c -- misc functions used in client and server
+
+#include "quakedef.h"
+
+#define NUM_SAFE_ARGVS  7
+
+static const char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
+static const char     *argvdummy = " ";
+
+static const char     *safeargvs[NUM_SAFE_ARGVS] =
+	{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};
+
+cvar_t	registered = CVAR2("registered","0");
+cvar_t  cmdline = CVAR4("cmdline","0", false, true);
+
+qboolean        com_modified;   // set true if using non-id files
+
+qboolean		proghack;
+
+int             static_registered = 1;  // only for startup check, then set
+
+qboolean		msg_suppress_1 = 0;
+
+void COM_InitFilesystem (void);
+
+// if a packfile directory differs from this, it is assumed to be hacked
+#define PAK0_COUNT              339
+#define PAK0_CRC                32981
+
+char	com_token[1024];
+int		com_argc;
+const char	**com_argv;
+
+#define CMDLINE_LENGTH	256
+char	com_cmdline[CMDLINE_LENGTH];
+
+qboolean		standard_quake = true, rogue, hipnotic;
+
+// this graphic needs to be in the pak file to use registered features
+unsigned short pop[] =
+{
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
+,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000
+,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000
+,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600
+,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563
+,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564
+,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564
+,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563
+,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500
+,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200
+,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000
+,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000
+,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000
+,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000
+,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000
+,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000
+};
+
+/*
+
+
+All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
+
+The "base directory" is the path to the directory holding the quake.exe and all game directories.  The sys_* files pass this to host_init in quakeparms_t->basedir.  This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory.  The base directory is
+only used during filesystem initialization.
+
+The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to.  This can be overridden with the "-game" command line parameter.  The game directory can never be changed while quake is executing.  This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
+
+The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines.  If there is a cache directory
+specified, when a file is found by the normal search path, it will be mirrored
+into the cache directory, then opened there.
+
+
+
+FIXME:
+The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently.  This could be used to add a "-sspeed 22050" for the high quality sound edition.  Because they are added at the end, they will not override an explicit setting on the original command line.
+
+*/
+
+//============================================================================
+
+
+// ClearLink is used for new headnodes
+void ClearLink (link_t *l)
+{
+	l->prev = l->next = l;
+}
+
+void RemoveLink (link_t *l)
+{
+	l->next->prev = l->prev;
+	l->prev->next = l->next;
+}
+
+void InsertLinkBefore (link_t *l, link_t *before)
+{
+	l->next = before;
+	l->prev = before->prev;
+	l->prev->next = l;
+	l->next->prev = l;
+}
+void InsertLinkAfter (link_t *l, link_t *after)
+{
+	l->next = after->next;
+	l->prev = after;
+	l->prev->next = l;
+	l->next->prev = l;
+}
+
+/*
+============================================================================
+
+					LIBRARY REPLACEMENT FUNCTIONS
+
+============================================================================
+*/
+
+void Q_memset (void *dest, int fill, int count)
+{
+	int             i;
+
+	if ( (((long)dest | count) & 3) == 0)
+	{
+		count >>= 2;
+		fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
+		for (i=0 ; i<count ; i++)
+			((int *)dest)[i] = fill;
+	}
+	else
+		for (i=0 ; i<count ; i++)
+			((byte *)dest)[i] = fill;
+}
+
+void Q_memcpy (void *dest, const void *src, int count)
+{
+	int             i;
+
+	if (( ( (long)dest | (long)src | count) & 3) == 0 )
+	{
+		count>>=2;
+		for (i=0 ; i<count ; i++)
+			((int *)dest)[i] = ((int *)src)[i];
+	}
+	else
+		for (i=0 ; i<count ; i++)
+			((byte *)dest)[i] = ((byte *)src)[i];
+}
+
+int Q_memcmp (const void *m1, const void *m2, int count)
+{
+	while(count)
+	{
+		count--;
+		if (((byte *)m1)[count] != ((byte *)m2)[count])
+			return -1;
+	}
+	return 0;
+}
+
+void Q_strcpy (char *dest, const char *src)
+{
+	while (*src)
+	{
+		*dest++ = *src++;
+	}
+	*dest++ = 0;
+}
+
+void Q_strncpy (char *dest, const char *src, int count)
+{
+	while (*src && count--)
+	{
+		*dest++ = *src++;
+	}
+	if (count)
+		*dest++ = 0;
+}
+
+int Q_strlen (const char *str)
+{
+	int             count;
+
+	count = 0;
+	while (str[count])
+		count++;
+
+	return count;
+}
+
+char *Q_strrchr(const char *s, char c)
+{
+    int len = Q_strlen(s);
+    s += len;
+    while (len--)
+	if (*--s == c) return (char*)  s;
+    return 0;
+}
+
+void Q_strcat (char *dest, const char *src)
+{
+	dest += Q_strlen(dest);
+	Q_strcpy (dest, src);
+}
+
+int Q_strcmp (const char *s1, const char *s2)
+{
+	while (1)
+	{
+		if (*s1 != *s2)
+			return -1;              // strings not equal
+		if (!*s1)
+			return 0;               // strings are equal
+		s1++;
+		s2++;
+	}
+
+	return -1;
+}
+
+int Q_strncmp (const char *s1, const char *s2, int count)
+{
+	while (1)
+	{
+		if (!count--)
+			return 0;
+		if (*s1 != *s2)
+			return -1;              // strings not equal
+		if (!*s1)
+			return 0;               // strings are equal
+		s1++;
+		s2++;
+	}
+
+	return -1;
+}
+
+int Q_strncasecmp (const char *s1, const char *s2, int n)
+{
+	int             c1, c2;
+
+	while (1)
+	{
+		c1 = *s1++;
+		c2 = *s2++;
+
+		if (!n--)
+			return 0;               // strings are equal until end point
+
+		if (c1 != c2)
+		{
+			if (c1 >= 'a' && c1 <= 'z')
+				c1 -= ('a' - 'A');
+			if (c2 >= 'a' && c2 <= 'z')
+				c2 -= ('a' - 'A');
+			if (c1 != c2)
+				return -1;              // strings not equal
+		}
+		if (!c1)
+			return 0;               // strings are equal
+//              s1++;
+//              s2++;
+	}
+
+	return -1;
+}
+
+int Q_strcasecmp (const char *s1, const char *s2)
+{
+	return Q_strncasecmp (s1, s2, 99999);
+}
+
+int Q_atoi (const char *str)
+{
+	int             val;
+	int             sign;
+	int             c;
+
+	if (*str == '-')
+	{
+		sign = -1;
+		str++;
+	}
+	else
+		sign = 1;
+
+	val = 0;
+
+//
+// check for hex
+//
+	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
+	{
+		str += 2;
+		while (1)
+		{
+			c = *str++;
+			if (c >= '0' && c <= '9')
+				val = (val<<4) + c - '0';
+			else if (c >= 'a' && c <= 'f')
+				val = (val<<4) + c - 'a' + 10;
+			else if (c >= 'A' && c <= 'F')
+				val = (val<<4) + c - 'A' + 10;
+			else
+				return val*sign;
+		}
+	}
+
+//
+// check for character
+//
+	if (str[0] == '\'')
+	{
+		return sign * str[1];
+	}
+
+//
+// assume decimal
+//
+	while (1)
+	{
+		c = *str++;
+		if (c <'0' || c > '9')
+			return val*sign;
+		val = val*10 + c - '0';
+	}
+
+	return 0;
+}
+
+
+float Q_atof (const char *str)
+{
+	double			val;
+	int             sign;
+	int             c;
+	int             decimal, total;
+
+	if (*str == '-')
+	{
+		sign = -1;
+		str++;
+	}
+	else
+		sign = 1;
+
+	val = 0;
+
+//
+// check for hex
+//
+	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
+	{
+		str += 2;
+		while (1)
+		{
+			c = *str++;
+			if (c >= '0' && c <= '9')
+				val = (val*16) + c - '0';
+			else if (c >= 'a' && c <= 'f')
+				val = (val*16) + c - 'a' + 10;
+			else if (c >= 'A' && c <= 'F')
+				val = (val*16) + c - 'A' + 10;
+			else
+				return val*sign;
+		}
+	}
+
+//
+// check for character
+//
+	if (str[0] == '\'')
+	{
+		return sign * str[1];
+	}
+
+//
+// assume decimal
+//
+	decimal = -1;
+	total = 0;
+	while (1)
+	{
+		c = *str++;
+		if (c == '.')
+		{
+			decimal = total;
+			continue;
+		}
+		if (c <'0' || c > '9')
+			break;
+		val = val*10 + c - '0';
+		total++;
+	}
+
+	if (decimal == -1)
+		return val*sign;
+	while (total > decimal)
+	{
+		val /= 10;
+		total--;
+	}
+
+	return val*sign;
+}
+
+/*
+============================================================================
+
+					BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+qboolean        bigendien;
+
+short   (*BigShort) (short l);
+short   (*LittleShort) (short l);
+int     (*BigLong) (int l);
+int     (*LittleLong) (int l);
+float   (*BigFloat) (float l);
+float   (*LittleFloat) (float l);
+
+short   ShortSwap (short l)
+{
+	byte    b1,b2;
+
+	b1 = l&255;
+	b2 = (l>>8)&255;
+
+	return (b1<<8) + b2;
+}
+
+short   ShortNoSwap (short l)
+{
+	return l;
+}
+
+int    LongSwap (int l)
+{
+	byte    b1,b2,b3,b4;
+
+	b1 = l&255;
+	b2 = (l>>8)&255;
+	b3 = (l>>16)&255;
+	b4 = (l>>24)&255;
+
+	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int     LongNoSwap (int l)
+{
+	return l;
+}
+
+float FloatSwap (float f)
+{
+	union
+	{
+		float   f;
+		byte    b[4];
+	} dat1, dat2;
+
+
+	dat1.f = f;
+	dat2.b[0] = dat1.b[3];
+	dat2.b[1] = dat1.b[2];
+	dat2.b[2] = dat1.b[1];
+	dat2.b[3] = dat1.b[0];
+	return dat2.f;
+}
+
+float FloatNoSwap (float f)
+{
+	return f;
+}
+
+/*
+==============================================================================
+
+			MESSAGE IO FUNCTIONS
+
+Handles byte ordering and avoids alignment errors
+==============================================================================
+*/
+
+//
+// writing functions
+//
+
+void MSG_WriteChar (sizebuf_t *sb, int c)
+{
+	byte    *buf;
+
+#ifdef PARANOID
+	if (c < -128 || c > 127)
+		Sys_Error ("MSG_WriteChar: range error");
+#endif
+
+	buf = (byte*) SZ_GetSpace (sb, 1);
+	buf[0] = c;
+}
+
+void MSG_WriteByte (sizebuf_t *sb, int c)
+{
+	byte    *buf;
+
+#ifdef PARANOID
+	if (c < 0 || c > 255)
+		Sys_Error ("MSG_WriteByte: range error");
+#endif
+
+	buf = (byte*) SZ_GetSpace (sb, 1);
+	buf[0] = c;
+}
+
+void MSG_WriteShort (sizebuf_t *sb, int c)
+{
+	byte    *buf;
+
+#ifdef PARANOID
+	if (c < ((short)0x8000) || c > (short)0x7fff)
+		Sys_Error ("MSG_WriteShort: range error");
+#endif
+
+	buf = (byte*) SZ_GetSpace (sb, 2);
+	buf[0] = c&0xff;
+	buf[1] = c>>8;
+}
+
+void MSG_WriteLong (sizebuf_t *sb, int c)
+{
+	byte    *buf;
+
+	buf = (byte*) SZ_GetSpace (sb, 4);
+	buf[0] = c&0xff;
+	buf[1] = (c>>8)&0xff;
+	buf[2] = (c>>16)&0xff;
+	buf[3] = c>>24;
+}
+
+void MSG_WriteFloat (sizebuf_t *sb, float f)
+{
+	union
+	{
+		float   f;
+		int     l;
+	} dat;
+
+
+	dat.f = f;
+	dat.l = LittleLong (dat.l);
+
+	SZ_Write (sb, &dat.l, 4);
+}
+
+void MSG_WriteString (sizebuf_t *sb, const char *s)
+{
+	if (!s)
+		SZ_Write (sb, "", 1);
+	else
+		SZ_Write (sb, s, Q_strlen(s)+1);
+}
+
+void MSG_WriteCoord (sizebuf_t *sb, float f)
+{
+	MSG_WriteShort (sb, (int)(f*8));
+}
+
+void MSG_WriteAngle (sizebuf_t *sb, float f)
+{
+	MSG_WriteByte (sb, ((int)f*256/360) & 255);
+}
+
+//
+// reading functions
+//
+int                     msg_readcount;
+qboolean        msg_badread;
+
+void MSG_BeginReading (void)
+{
+	msg_readcount = 0;
+	msg_badread = false;
+}
+
+// returns -1 and sets msg_badread if no more characters are available
+int MSG_ReadChar (void)
+{
+	int     c;
+
+	if (msg_readcount+1 > net_message.cursize)
+	{
+		msg_badread = true;
+		return -1;
+	}
+
+	c = (signed char)net_message.data[msg_readcount];
+	msg_readcount++;
+
+	return c;
+}
+
+int MSG_ReadByte (void)
+{
+	int     c;
+
+	if (msg_readcount+1 > net_message.cursize)
+	{
+		msg_badread = true;
+		return -1;
+	}
+
+	c = (unsigned char)net_message.data[msg_readcount];
+	msg_readcount++;
+
+	return c;
+}
+
+int MSG_ReadShort (void)
+{
+	int     c;
+
+	if (msg_readcount+2 > net_message.cursize)
+	{
+		msg_badread = true;
+		return -1;
+	}
+
+	c = (short)(net_message.data[msg_readcount]
+	+ (net_message.data[msg_readcount+1]<<8));
+
+	msg_readcount += 2;
+
+	return c;
+}
+
+int MSG_ReadLong (void)
+{
+	int     c;
+
+	if (msg_readcount+4 > net_message.cursize)
+	{
+		msg_badread = true;
+		return -1;
+	}
+
+	c = net_message.data[msg_readcount]
+	+ (net_message.data[msg_readcount+1]<<8)
+	+ (net_message.data[msg_readcount+2]<<16)
+	+ (net_message.data[msg_readcount+3]<<24);
+
+	msg_readcount += 4;
+
+	return c;
+}
+
+float MSG_ReadFloat (void)
+{
+	union
+	{
+		byte    b[4];
+		float   f;
+		int     l;
+	} dat;
+
+	dat.b[0] =      net_message.data[msg_readcount];
+	dat.b[1] =      net_message.data[msg_readcount+1];
+	dat.b[2] =      net_message.data[msg_readcount+2];
+	dat.b[3] =      net_message.data[msg_readcount+3];
+	msg_readcount += 4;
+
+	dat.l = LittleLong (dat.l);
+
+	return dat.f;
+}
+
+char *MSG_ReadString (void)
+{
+	static char     string[2048];
+	int             l,c;
+
+	l = 0;
+	do
+	{
+		c = MSG_ReadChar ();
+		if (c == -1 || c == 0)
+			break;
+		string[l] = c;
+		l++;
+	} while (l < (int) (sizeof(string)-1));
+
+	string[l] = 0;
+
+	return string;
+}
+
+float MSG_ReadCoord (void)
+{
+	return MSG_ReadShort() * (1.0/8);
+}
+
+float MSG_ReadAngle (void)
+{
+	return MSG_ReadChar() * (360.0/256);
+}
+
+
+
+//===========================================================================
+
+void SZ_Alloc (sizebuf_t *buf, int startsize)
+{
+	if (startsize < 256)
+		startsize = 256;
+	buf->data = (byte*) Hunk_AllocName (startsize, "sizebuf");
+	buf->maxsize = startsize;
+	buf->cursize = 0;
+}
+
+
+void SZ_Free (sizebuf_t *buf)
+{
+//      Z_Free (buf->data);
+//      buf->data = NULL;
+//      buf->maxsize = 0;
+	buf->cursize = 0;
+}
+
+void SZ_Clear (sizebuf_t *buf)
+{
+	buf->cursize = 0;
+}
+
+void *SZ_GetSpace (sizebuf_t *buf, int length)
+{
+	void    *data;
+
+	if (buf->cursize + length > buf->maxsize)
+	{
+		if (!buf->allowoverflow)
+			Sys_Error ("SZ_GetSpace: overflow without allowoverflow set");
+
+		if (length > buf->maxsize)
+			Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
+
+		buf->overflowed = true;
+		Con_Printf ("SZ_GetSpace: overflow");
+		SZ_Clear (buf);
+	}
+
+	data = buf->data + buf->cursize;
+	buf->cursize += length;
+
+	return data;
+}
+
+void SZ_Write (sizebuf_t *buf, const void *data, int length)
+{
+	Q_memcpy (SZ_GetSpace(buf,length),data,length);
+}
+
+void SZ_Print (sizebuf_t *buf, const char *data)
+{
+	int             len;
+
+	len = Q_strlen(data)+1;
+
+// byte * cast to keep VC++ happy
+	if (buf->data[buf->cursize-1])
+		Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
+	else
+		Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
+}
+
+
+//============================================================================
+
+
+/*
+============
+COM_SkipPath
+============
+*/
+const char *COM_SkipPath (const char *pathname)
+{
+	const char    *last;
+
+	last = pathname;
+	while (*pathname)
+	{
+		if (*pathname=='/')
+			last = pathname+1;
+		pathname++;
+	}
+	return last;
+}
+
+/*
+============
+COM_StripExtension
+============
+*/
+void COM_StripExtension (const char *in, char *out)
+{
+	while (*in && *in != '.')
+		*out++ = *in++;
+	*out = 0;
+}
+
+/*
+============
+COM_FileExtension
+============
+*/
+const char *COM_FileExtension (const char *in)
+{
+	static char exten[8];
+	int             i;
+
+	while (*in && *in != '.')
+		in++;
+	if (!*in)
+		return "";
+	in++;
+	for (i=0 ; i<7 && *in ; i++,in++)
+		exten[i] = *in;
+	exten[i] = 0;
+	return exten;
+}
+
+/*
+============
+COM_FileBase
+============
+*/
+void COM_FileBase (const char *in, char *out, size_t outSize)
+{
+	// Get the "base" part of a path, make sure we don't exceed outSize bytes
+
+	const char* start;
+	const char* end;
+	size_t len;
+
+	if(!outSize)
+		return;
+
+	start = strrchr(in, '/');
+	if(start)
+	{
+		start++;
+	}
+	else
+	{
+		start = in;
+	}
+
+	// Start now points to the beginning of the filename part of the file.
+
+	end = strrchr(start, '.');
+
+	if(!end)
+	{
+		end = start + strlen(start);
+	}
+
+	// end now points one character beyond the end of the base part of the file.
+
+	len = end - start;
+	if(len > outSize - 1)
+		len = outSize - 1;
+
+	memcpy(out, start, len);
+	out[len] = 0;
+}
+
+
+/*
+==================
+COM_DefaultExtension
+==================
+*/
+void COM_DefaultExtension (char *path, const char *extension)
+{
+	char    *src;
+//
+// if path doesn't have a .EXT, append extension
+// (extension should include the .)
+//
+	src = path + strlen(path) - 1;
+
+	while (*src != '/' && src != path)
+	{
+		if (*src == '.')
+			return;                 // it has an extension
+		src--;
+	}
+
+	strcat (path, extension);
+}
+
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+==============
+*/
+char *COM_Parse (char *data)
+{
+	int             c;
+	int             len;
+
+	len = 0;
+	com_token[0] = 0;
+
+	if (!data)
+		return NULL;
+
+// skip whitespace
+skipwhite:
+	while ( (c = *data) <= ' ')
+	{
+		if (c == 0)
+			return NULL;                    // end of file;
+		data++;
+	}
+
+// skip // comments
+	if (c=='/' && data[1] == '/')
+	{
+		while (*data && *data != '\n')
+			data++;
+		goto skipwhite;
+	}
+
+
+// handle quoted strings specially
+	if (c == '\"')
+	{
+		data++;
+		while (1)
+		{
+			c = *data++;
+			if (c=='\"' || !c)
+			{
+				com_token[len] = 0;
+				return data;
+			}
+			com_token[len] = c;
+			len++;
+		}
+	}
+
+// parse single characters
+	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+	{
+		com_token[len] = c;
+		len++;
+		com_token[len] = 0;
+		return data+1;
+	}
+
+// parse a regular word
+	do
+	{
+		com_token[len] = c;
+		data++;
+		len++;
+		c = *data;
+	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+			break;
+	} while (c>32);
+
+	com_token[len] = 0;
+	return data;
+}
+
+
+/*
+================
+COM_CheckParm
+
+Returns the position (1 to argc-1) in the program's argument list
+where the given parameter apears, or 0 if not present
+================
+*/
+int COM_CheckParm (const char *parm)
+{
+	int             i;
+
+	for (i=1 ; i<com_argc ; i++)
+	{
+		if (!com_argv[i])
+			continue;               // NEXTSTEP sometimes clears appkit vars.
+		if (!Q_strcmp (parm,com_argv[i]))
+			return i;
+	}
+
+	return 0;
+}
+
+/*
+================
+COM_CheckRegistered
+
+Looks for the pop.txt file and verifies it.
+Sets the "registered" cvar.
+Immediately exits out if an alternate game was attempted to be started without
+being registered.
+================
+*/
+void COM_CheckRegistered (void)
+{
+	int             h;
+	unsigned short  check[128];
+	int                     i;
+
+	COM_OpenFile("gfx/pop.lmp", &h);
+	static_registered = 0;
+
+	if (h == -1)
+	{
+#if WINDED
+	Sys_Error ("This dedicated server requires a full registered copy of Quake");
+#endif
+		Con_Printf ("Playing shareware version.\n");
+		if (com_modified)
+			Sys_Error ("You must have the registered version to use modified games");
+
+#ifdef USE_OPENGLES
+		// For development purposes pretend we're registered. This allows glquake
+		// file caching to work:
+
+		static_registered = 1;
+#endif // USE_OPENGLES
+		return;
+	}
+
+	Sys_FileRead (h, check, sizeof(check));
+	COM_CloseFile (h);
+
+	for (i=0 ; i<128 ; i++)
+		if (pop[i] != (unsigned short)BigShort (check[i]))
+			Sys_Error ("Corrupted data file.");
+
+	Cvar_Set ("cmdline", com_cmdline);
+	Cvar_Set ("registered", "1");
+	static_registered = 1;
+	Con_Printf ("Playing registered version.\n");
+}
+
+
+void COM_Path_f (void);
+
+
+/*
+================
+COM_InitArgv
+================
+*/
+void COM_InitArgv (int argc, const char **argv)
+{
+	qboolean        safe;
+	int             i, j, n;
+
+// reconstitute the command line for the cmdline externally visible cvar
+	n = 0;
+
+	for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)
+	{
+		i = 0;
+
+		while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
+		{
+			com_cmdline[n++] = argv[j][i++];
+		}
+
+		if (n < (CMDLINE_LENGTH - 1))
+			com_cmdline[n++] = ' ';
+		else
+			break;
+	}
+
+	com_cmdline[n] = 0;
+
+	safe = false;
+
+	for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
+		 com_argc++)
+	{
+		largv[com_argc] = argv[com_argc];
+		if (!Q_strcmp ("-safe", argv[com_argc]))
+			safe = true;
+	}
+
+	if (safe)
+	{
+	// force all the safe-mode switches. Note that we reserved extra space in
+	// case we need to add these, so we don't need an overflow check
+		for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
+		{
+			largv[com_argc] = safeargvs[i];
+			com_argc++;
+		}
+	}
+
+	largv[com_argc] = argvdummy;
+	com_argv = largv;
+
+	if (COM_CheckParm ("-rogue"))
+	{
+		rogue = true;
+		standard_quake = false;
+	}
+
+	if (COM_CheckParm ("-hipnotic"))
+	{
+		hipnotic = true;
+		standard_quake = false;
+	}
+}
+
+
+/*
+================
+COM_Init
+================
+*/
+
+typedef union swapTest_ {
+    byte b[2];
+    short s;
+} swapTest;
+
+void COM_Init (const char *basedir)
+{
+	swapTest swaptest;
+	swaptest.b[0] = 1;
+	swaptest.b[1] = 0;
+
+// set the byte swapping variables in a portable manner
+	if ( swaptest.s == 1)
+	{
+		bigendien = false;
+		BigShort = ShortSwap;
+		LittleShort = ShortNoSwap;
+		BigLong = LongSwap;
+		LittleLong = LongNoSwap;
+		BigFloat = FloatSwap;
+		LittleFloat = FloatNoSwap;
+	}
+	else
+	{
+		bigendien = true;
+		BigShort = ShortNoSwap;
+		LittleShort = ShortSwap;
+		BigLong = LongNoSwap;
+		LittleLong = LongSwap;
+		BigFloat = FloatNoSwap;
+		LittleFloat = FloatSwap;
+	}
+
+	Cvar_RegisterVariable (&registered);
+	Cvar_RegisterVariable (&cmdline);
+	Cmd_AddCommand ("path", COM_Path_f);
+
+	COM_InitFilesystem ();
+	COM_CheckRegistered ();
+}
+
+
+/*
+============
+va
+
+does a varargs printf into a temp buffer, so I don't need to have
+varargs versions of all text functions.
+FIXME: make this buffer size safe someday
+============
+*/
+char    *va(const char *format, ...)
+{
+	va_list         argptr;
+	static char             string[1024];
+
+	va_start (argptr, format);
+	vsprintf (string, format,argptr);
+	va_end (argptr);
+
+	return string;
+}
+
+
+/// just for debugging
+int     memsearch (const byte *start, int count, int search)
+{
+	int             i;
+
+	for (i=0 ; i<count ; i++)
+		if (start[i] == search)
+			return i;
+	return -1;
+}
+
+/*
+=============================================================================
+
+QUAKE FILESYSTEM
+
+=============================================================================
+*/
+
+int     com_filesize;
+
+
+//
+// in memory
+//
+
+typedef struct
+{
+	char    name[MAX_QPATH];
+	int             filepos, filelen;
+} packfile_t;
+
+typedef struct pack_s
+{
+	char    filename[MAX_OSPATH];
+	int             handle;
+	int             numfiles;
+	packfile_t      *files;
+} pack_t;
+
+//
+// on disk
+//
+typedef struct
+{
+	char    name[56];
+	int             filepos, filelen;
+} dpackfile_t;
+
+typedef struct
+{
+	char    id[4];
+	int             dirofs;
+	int             dirlen;
+} dpackheader_t;
+
+#define MAX_FILES_IN_PACK       2048
+
+char    com_cachedir[MAX_OSPATH];
+char    com_gamedir[MAX_OSPATH];
+
+typedef struct searchpath_s
+{
+	char    filename[MAX_OSPATH];
+	pack_t  *pack;          // only one of filename / pack will be used
+	struct searchpath_s *next;
+} searchpath_t;
+
+searchpath_t    *com_searchpaths;
+
+/*
+============
+COM_Path_f
+
+============
+*/
+void COM_Path_f (void)
+{
+	searchpath_t    *s;
+
+	Con_Printf ("Current search path:\n");
+	for (s=com_searchpaths ; s ; s=s->next)
+	{
+		if (s->pack)
+		{
+			Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
+		}
+		else
+			Con_Printf ("%s\n", s->filename);
+	}
+}
+
+/*
+============
+COM_WriteFile
+
+The filename will be prefixed by the current game directory
+============
+*/
+void COM_WriteFile (const char *filename, void *data, int len)
+{
+	int             handle;
+	char    name[MAX_OSPATH];
+
+	sprintf (name, "%s/%s", com_gamedir, filename);
+
+	handle = Sys_FileOpenWrite (name);
+	if (handle == -1)
+	{
+		Sys_Printf ("COM_WriteFile: failed on %s\n", name);
+		return;
+	}
+
+	Sys_Printf ("COM_WriteFile: %s\n", name);
+	Sys_FileWrite (handle, data, len);
+	Sys_FileClose (handle);
+}
+
+
+/*
+============
+COM_CreatePath
+
+Only used for CopyFile
+============
+*/
+void    COM_CreatePath (const char *path)
+{
+    char    *ofs;
+
+	for (ofs = (char*) path+1 ; *ofs ; ofs++)
+	{
+		if (*ofs == '/')
+		{       // create the directory
+			*ofs = 0;
+			Sys_mkdir (path);
+			*ofs = '/';
+		}
+	}
+}
+
+
+/*
+===========
+COM_CopyFile
+
+Copies a file over from the net to the local cache, creating any directories
+needed.  This is for the convenience of developers using ISDN from home.
+===========
+*/
+void COM_CopyFile (const char *netpath, const char *cachepath)
+{
+	int             in, out;
+	int             remaining, count;
+	char    buf[4096];
+
+	remaining = Sys_FileOpenRead (netpath, &in);
+	COM_CreatePath (cachepath);     // create directories up to the cache file
+	out = Sys_FileOpenWrite (cachepath);
+
+	while (remaining)
+	{
+		if (remaining < (int) sizeof(buf))
+			count = remaining;
+		else
+			count = sizeof(buf);
+		Sys_FileRead (in, buf, count);
+		Sys_FileWrite (out, buf, count);
+		remaining -= count;
+	}
+
+	Sys_FileClose (in);
+	Sys_FileClose (out);
+}
+
+/*
+===========
+COM_FindFile
+
+Finds the file in the search path.
+Sets com_filesize and one of handle or file
+===========
+*/
+int COM_FindFile (const char *filename, int *handle, FILE **file)
+{
+	searchpath_t    *search;
+	char            netpath[MAX_OSPATH];
+	char            cachepath[MAX_OSPATH];
+	pack_t          *pak;
+	int                     i;
+	int                     findtime, cachetime;
+
+	if (file && handle)
+		Sys_Error ("COM_FindFile: both handle and file set");
+	if (!file && !handle)
+		Sys_Error ("COM_FindFile: neither handle or file set");
+
+//
+// search through the path, one element at a time
+//
+	search = com_searchpaths;
+	if (proghack)
+	{	// gross hack to use quake 1 progs with quake 2 maps
+		if (!strcmp(filename, "progs.dat"))
+			search = search->next;
+	}
+
+	for ( ; search ; search = search->next)
+	{
+	// is the element a pak file?
+		if (search->pack)
+		{
+		// look through all the pak file elements
+			pak = search->pack;
+			for (i=0 ; i<pak->numfiles ; i++)
+				if (!strcmp (pak->files[i].name, filename))
+				{       // found it!
+					// Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);
+					if (handle)
+					{
+						*handle = pak->handle;
+						Sys_FileSeek (pak->handle, pak->files[i].filepos);
+					}
+					else
+					{       // open a new file on the pakfile
+						*file = fopen (pak->filename, "rb");
+						if (*file)
+							fseek (*file, pak->files[i].filepos, SEEK_SET);
+					}
+					com_filesize = pak->files[i].filelen;
+					return com_filesize;
+				}
+		}
+		else
+		{
+	// check a file in the directory tree
+			if (!static_registered)
+			{       // if not a registered version, don't ever go beyond base
+				if ( strchr (filename, '/') || strchr (filename,'\\'))
+					continue;
+			}
+
+			sprintf (netpath, "%s/%s",search->filename, filename);
+
+			findtime = Sys_FileTime (netpath);
+			if (findtime == -1)
+				continue;
+
+		// see if the file needs to be updated in the cache
+			if (!com_cachedir[0])
+				strcpy (cachepath, netpath);
+			else
+			{
+#if defined(_WIN32)
+				if ((strlen(netpath) < 2) || (netpath[1] != ':'))
+					sprintf (cachepath,"%s%s", com_cachedir, netpath);
+				else
+					sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
+#else
+				sprintf (cachepath,"%s%s", com_cachedir, netpath);
+#endif
+
+				cachetime = Sys_FileTime (cachepath);
+
+				if (cachetime < findtime)
+					COM_CopyFile (netpath, cachepath);
+				strcpy (netpath, cachepath);
+			}
+
+			// Sys_Printf ("FindFile: %s\n",netpath);
+			com_filesize = Sys_FileOpenRead (netpath, &i);
+			if (handle)
+				*handle = i;
+			else
+			{
+				Sys_FileClose (i);
+				*file = fopen (netpath, "rb");
+			}
+			return com_filesize;
+		}
+
+	}
+
+	Sys_Printf ("FindFile: can't find %s\n", filename);
+
+	if (handle)
+		*handle = -1;
+	else
+		*file = NULL;
+	com_filesize = -1;
+	return -1;
+}
+
+
+/*
+===========
+COM_OpenFile
+
+filename never has a leading slash, but may contain directory walks
+returns a handle and a length
+it may actually be inside a pak file
+===========
+*/
+int COM_OpenFile (const char *filename, int *handle)
+{
+	return COM_FindFile (filename, handle, NULL);
+}
+
+/*
+===========
+COM_FOpenFile
+
+If the requested file is inside a packfile, a new FILE * will be opened
+into the file.
+===========
+*/
+int COM_FOpenFile (const char *filename, FILE **file)
+{
+	return COM_FindFile (filename, NULL, file);
+}
+
+/*
+============
+COM_CloseFile
+
+If it is a pak file handle, don't really close it
+============
+*/
+void COM_CloseFile (int h)
+{
+	searchpath_t    *s;
+
+	for (s = com_searchpaths ; s ; s=s->next)
+		if (s->pack && s->pack->handle == h)
+			return;
+
+	Sys_FileClose (h);
+}
+
+
+/*
+============
+COM_LoadFile
+
+Filename are reletive to the quake directory.
+Allways appends a 0 byte.
+============
+*/
+cache_user_t *loadcache;
+byte    *loadbuf;
+int             loadsize;
+byte *COM_LoadFile (const char *path, int usehunk)
+{
+	int             h;
+	byte    *buf;
+	char    base[32];
+	int             len;
+
+	buf = NULL;     // quiet compiler warning
+
+// look for it in the filesystem or pack files
+	len = COM_OpenFile (path, &h);
+	if (h == -1)
+		return NULL;
+
+// extract the filename base name for hunk tag
+	COM_FileBase (path, base, sizeof(base));
+
+	if (usehunk == 1)
+		buf = (byte*) Hunk_AllocName (len+1, base);
+	else if (usehunk == 2)
+		buf = (byte*) Hunk_TempAlloc (len+1);
+	else if (usehunk == 0)
+		buf = (byte*) Z_Malloc (len+1);
+	else if (usehunk == 3)
+		buf = (byte*) Cache_Alloc (loadcache, len+1, base);
+	else if (usehunk == 4)
+	{
+		if (len+1 > loadsize)
+			buf = (byte*) Hunk_TempAlloc (len+1);
+		else
+			buf = loadbuf;
+	}
+	else
+		Sys_Error ("COM_LoadFile: bad usehunk");
+
+	if (!buf)
+		Sys_Error ("COM_LoadFile: not enough space for %s", path);
+
+	((byte *)buf)[len] = 0;
+
+	Draw_BeginDisc ();
+	Sys_FileRead (h, buf, len);
+	COM_CloseFile (h);
+	Draw_EndDisc ();
+
+	return buf;
+}
+
+byte *COM_LoadHunkFile (const char *path)
+{
+	return COM_LoadFile (path, 1);
+}
+
+byte *COM_LoadTempFile (const char *path)
+{
+	return COM_LoadFile (path, 2);
+}
+
+void COM_LoadCacheFile (char *path, struct cache_user_s *cu)
+{
+	loadcache = cu;
+	COM_LoadFile (path, 3);
+}
+
+// uses temp hunk if larger than bufsize
+byte *COM_LoadStackFile (const char *path, void *buffer, int bufsize)
+{
+	byte    *buf;
+
+	loadbuf = (byte *)buffer;
+	loadsize = bufsize;
+	buf = COM_LoadFile (path, 4);
+
+	return buf;
+}
+
+/*
+=================
+COM_LoadPackFile
+
+Takes an explicit (not game tree related) path to a pak file.
+
+Loads the header and directory, adding the files at the beginning
+of the list so they override previous pack files.
+=================
+*/
+pack_t *COM_LoadPackFile (const char *packfile)
+{
+	dpackheader_t   header;
+	int                             i;
+	packfile_t              *newfiles;
+	int                             numpackfiles;
+	pack_t                  *pack;
+	int                             packhandle;
+	dpackfile_t             info[MAX_FILES_IN_PACK];
+	unsigned short          crc;
+
+	if (Sys_FileOpenRead (packfile, &packhandle) == -1)
+	{
+//              Con_Printf ("Couldn't open %s\n", packfile);
+		return NULL;
+	}
+	Sys_FileRead (packhandle, (void *)&header, sizeof(header));
+	if (header.id[0] != 'P' || header.id[1] != 'A'
+	|| header.id[2] != 'C' || header.id[3] != 'K')
+		Sys_Error ("%s is not a packfile", packfile);
+	header.dirofs = LittleLong (header.dirofs);
+	header.dirlen = LittleLong (header.dirlen);
+
+	numpackfiles = header.dirlen / sizeof(dpackfile_t);
+
+	if (numpackfiles > MAX_FILES_IN_PACK)
+		Sys_Error ("%s has %i files", packfile, numpackfiles);
+
+	if (numpackfiles != PAK0_COUNT)
+		com_modified = true;    // not the original file
+
+	newfiles = (packfile_t*) Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile");
+
+	Sys_FileSeek (packhandle, header.dirofs);
+	Sys_FileRead (packhandle, (void *)info, header.dirlen);
+
+// crc the directory to check for modifications
+	CRC_Init (&crc);
+	for (i=0 ; i<header.dirlen ; i++)
+		CRC_ProcessByte (&crc, ((byte *)info)[i]);
+	if (crc != PAK0_CRC)
+		com_modified = true;
+
+// parse the directory
+	for (i=0 ; i<numpackfiles ; i++)
+	{
+		strcpy (newfiles[i].name, info[i].name);
+		newfiles[i].filepos = LittleLong(info[i].filepos);
+		newfiles[i].filelen = LittleLong(info[i].filelen);
+	}
+
+	pack = (pack_t*) Hunk_Alloc (sizeof (pack_t));
+	strcpy (pack->filename, packfile);
+	pack->handle = packhandle;
+	pack->numfiles = numpackfiles;
+	pack->files = newfiles;
+
+	Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
+	return pack;
+}
+
+
+/*
+================
+COM_AddGameDirectory
+
+Sets com_gamedir, adds the directory to the head of the path,
+then loads and adds pak1.pak pak2.pak ...
+================
+*/
+void COM_AddGameDirectory (char *dir)
+{
+	int                             i;
+	searchpath_t    *search;
+	pack_t                  *pak;
+	char                    pakfile[MAX_OSPATH];
+
+	strcpy (com_gamedir, dir);
+
+//
+// add the directory to the search path
+//
+	search = (searchpath_t*) Hunk_Alloc (sizeof(searchpath_t));
+	strcpy (search->filename, dir);
+	search->next = com_searchpaths;
+	com_searchpaths = search;
+
+//
+// add any pak files in the format pak0.pak pak1.pak, ...
+//
+	for (i=0 ; ; i++)
+	{
+		sprintf (pakfile, "%s/pak%i.pak", dir, i);
+		pak = COM_LoadPackFile (pakfile);
+		if (!pak)
+			break;
+		search = (searchpath_t*) Hunk_Alloc (sizeof(searchpath_t));
+		search->pack = pak;
+		search->next = com_searchpaths;
+		com_searchpaths = search;
+	}
+
+//
+// add the contents of the parms.txt file to the end of the command line
+//
+
+}
+
+/*
+================
+COM_InitFilesystem
+================
+*/
+void COM_InitFilesystem (void)
+{
+	int             i, j;
+	char    basedir[MAX_OSPATH];
+	searchpath_t    *search;
+
+//
+// -basedir <path>
+// Overrides the system supplied base directory (under GAMENAME)
+//
+	i = COM_CheckParm ("-basedir");
+	if (i && i < com_argc-1)
+		strcpy (basedir, com_argv[i+1]);
+	else
+		strcpy (basedir, host_parms.basedir);
+
+	j = strlen (basedir);
+
+	if (j > 0)
+	{
+		if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
+			basedir[j-1] = 0;
+	}
+
+//
+// -cachedir <path>
+// Overrides the system supplied cache directory (NULL or /qcache)
+// -cachedir - will disable caching.
+//
+	i = COM_CheckParm ("-cachedir");
+	if (i && i < com_argc-1)
+	{
+		if (com_argv[i+1][0] == '-')
+			com_cachedir[0] = 0;
+		else
+			strcpy (com_cachedir, com_argv[i+1]);
+	}
+	else if (host_parms.cachedir)
+		strcpy (com_cachedir, host_parms.cachedir);
+	else
+		com_cachedir[0] = 0;
+
+//
+// start up with GAMENAME by default (id1)
+//
+	COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
+
+	if (COM_CheckParm ("-rogue"))
+		COM_AddGameDirectory (va("%s/rogue", basedir) );
+	if (COM_CheckParm ("-hipnotic"))
+		COM_AddGameDirectory (va("%s/hipnotic", basedir) );
+
+//
+// -game <gamedir>
+// Adds basedir/gamedir as an override game
+//
+	i = COM_CheckParm ("-game");
+	if (i && i < com_argc-1)
+	{
+		com_modified = true;
+		COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
+	}
+
+//
+// -path <dir or packfile> [<dir or packfile>] ...
+// Fully specifies the exact serach path, overriding the generated one
+//
+	i = COM_CheckParm ("-path");
+	if (i)
+	{
+		com_modified = true;
+		com_searchpaths = NULL;
+		while (++i < com_argc)
+		{
+			if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
+				break;
+
+			search = (searchpath_t*) Hunk_Alloc (sizeof(searchpath_t));
+			if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
+			{
+				search->pack = COM_LoadPackFile (com_argv[i]);
+				if (!search->pack)
+					Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
+			}
+			else
+				strcpy (search->filename, com_argv[i]);
+			search->next = com_searchpaths;
+			com_searchpaths = search;
+		}
+	}
+
+	if (COM_CheckParm ("-proghack"))
+		proghack = true;
+}
+
+
diff --git a/quake/src/WinQuake/common.h b/quake/src/WinQuake/common.h
index 0a2f874..0655dab 100644
--- a/quake/src/WinQuake/common.h
+++ b/quake/src/WinQuake/common.h
@@ -1,183 +1,188 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// comndef.h  -- general definitions

-

-#if !defined BYTE_DEFINED

-typedef unsigned char 		byte;

-#define BYTE_DEFINED 1

-#endif

-

-#undef true

-#undef false

-

-typedef enum {false, true}	qboolean;

-

-//============================================================================

-

-typedef struct sizebuf_s

-{

-	qboolean	allowoverflow;	// if false, do a Sys_Error

-	qboolean	overflowed;		// set to true if the buffer size failed

-	byte	*data;

-	int		maxsize;

-	int		cursize;

-} sizebuf_t;

-

-void SZ_Alloc (sizebuf_t *buf, int startsize);

-void SZ_Free (sizebuf_t *buf);

-void SZ_Clear (sizebuf_t *buf);

-void *SZ_GetSpace (sizebuf_t *buf, int length);

-void SZ_Write (sizebuf_t *buf, void *data, int length);

-void SZ_Print (sizebuf_t *buf, char *data);	// strcats onto the sizebuf

-

-//============================================================================

-

-typedef struct link_s

-{

-	struct link_s	*prev, *next;

-} link_t;

-

-

-void ClearLink (link_t *l);

-void RemoveLink (link_t *l);

-void InsertLinkBefore (link_t *l, link_t *before);

-void InsertLinkAfter (link_t *l, link_t *after);

-

-// (type *)STRUCT_FROM_LINK(link_t *link, type, member)

-// ent = STRUCT_FROM_LINK(link,entity_t,order)

-// FIXME: remove this mess!

-#define	STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))

-

-//============================================================================

-

-#ifndef NULL

-#define NULL ((void *)0)

-#endif

-

-#define Q_MAXCHAR ((char)0x7f)

-#define Q_MAXSHORT ((short)0x7fff)

-#define Q_MAXINT	((int)0x7fffffff)

-#define Q_MAXLONG ((int)0x7fffffff)

-#define Q_MAXFLOAT ((int)0x7fffffff)

-

-#define Q_MINCHAR ((char)0x80)

-#define Q_MINSHORT ((short)0x8000)

-#define Q_MININT 	((int)0x80000000)

-#define Q_MINLONG ((int)0x80000000)

-#define Q_MINFLOAT ((int)0x7fffffff)

-

-//============================================================================

-

-extern	qboolean		bigendien;

-

-extern	short	(*BigShort) (short l);

-extern	short	(*LittleShort) (short l);

-extern	int	(*BigLong) (int l);

-extern	int	(*LittleLong) (int l);

-extern	float	(*BigFloat) (float l);

-extern	float	(*LittleFloat) (float l);

-

-//============================================================================

-

-void MSG_WriteChar (sizebuf_t *sb, int c);

-void MSG_WriteByte (sizebuf_t *sb, int c);

-void MSG_WriteShort (sizebuf_t *sb, int c);

-void MSG_WriteLong (sizebuf_t *sb, int c);

-void MSG_WriteFloat (sizebuf_t *sb, float f);

-void MSG_WriteString (sizebuf_t *sb, char *s);

-void MSG_WriteCoord (sizebuf_t *sb, float f);

-void MSG_WriteAngle (sizebuf_t *sb, float f);

-

-extern	int			msg_readcount;

-extern	qboolean	msg_badread;		// set if a read goes beyond end of message

-

-void MSG_BeginReading (void);

-int MSG_ReadChar (void);

-int MSG_ReadByte (void);

-int MSG_ReadShort (void);

-int MSG_ReadLong (void);

-float MSG_ReadFloat (void);

-char *MSG_ReadString (void);

-

-float MSG_ReadCoord (void);

-float MSG_ReadAngle (void);

-

-//============================================================================

-

-void Q_memset (void *dest, int fill, int count);

-void Q_memcpy (void *dest, void *src, int count);

-int Q_memcmp (void *m1, void *m2, int count);

-void Q_strcpy (char *dest, char *src);

-void Q_strncpy (char *dest, char *src, int count);

-int Q_strlen (char *str);

-char *Q_strrchr (char *s, char c);

-void Q_strcat (char *dest, char *src);

-int Q_strcmp (char *s1, char *s2);

-int Q_strncmp (char *s1, char *s2, int count);

-int Q_strcasecmp (char *s1, char *s2);

-int Q_strncasecmp (char *s1, char *s2, int n);

-int	Q_atoi (char *str);

-float Q_atof (char *str);

-

-//============================================================================

-

-extern	char		com_token[1024];

-extern	qboolean	com_eof;

-

-char *COM_Parse (char *data);

-

-

-extern	int		com_argc;

-extern	char	**com_argv;

-

-int COM_CheckParm (char *parm);

-void COM_Init (char *path);

-void COM_InitArgv (int argc, char **argv);

-

-char *COM_SkipPath (char *pathname);

-void COM_StripExtension (char *in, char *out);

-void COM_FileBase (char *in, char *out);

-void COM_DefaultExtension (char *path, char *extension);

-

-char	*va(char *format, ...);

-// does a varargs printf into a temp buffer

-

-

-//============================================================================

-

-extern int com_filesize;

-struct cache_user_s;

-

-extern	char	com_gamedir[MAX_OSPATH];

-

-void COM_WriteFile (char *filename, void *data, int len);

-int COM_OpenFile (char *filename, int *hndl);

-int COM_FOpenFile (char *filename, FILE **file);

-void COM_CloseFile (int h);

-

-byte *COM_LoadStackFile (char *path, void *buffer, int bufsize);

-byte *COM_LoadTempFile (char *path);

-byte *COM_LoadHunkFile (char *path);

-void COM_LoadCacheFile (char *path, struct cache_user_s *cu);

-

-

-extern	struct cvar_s	registered;

-

-extern qboolean		standard_quake, rogue, hipnotic;

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// comndef.h  -- general definitions
+
+#if !defined BYTE_DEFINED
+typedef unsigned char 		byte;
+#define BYTE_DEFINED 1
+#endif
+
+// #undef true
+// #undef false
+// typedef enum _qboolean {false, true} qboolean;
+
+// NOTE: qboolean must not be typedefed as a C++ bool because it is
+// used to store values other than 0 or 1 in the global array "used". See
+// the implementation of FanLength()
+
+typedef unsigned int qboolean;
+
+//============================================================================
+
+typedef struct sizebuf_s
+{
+	qboolean	allowoverflow;	// if false, do a Sys_Error
+	qboolean	overflowed;		// set to true if the buffer size failed
+	byte	*data;
+	int		maxsize;
+	int		cursize;
+} sizebuf_t;
+
+void SZ_Alloc (sizebuf_t *buf, int startsize);
+void SZ_Free (sizebuf_t *buf);
+void SZ_Clear (sizebuf_t *buf);
+void *SZ_GetSpace (sizebuf_t *buf, int length);
+void SZ_Write (sizebuf_t *buf, const void *data, int length);
+void SZ_Print (sizebuf_t *buf, const char *data);	// strcats onto the sizebuf
+
+//============================================================================
+
+typedef struct link_s
+{
+	struct link_s	*prev, *next;
+} link_t;
+
+
+void ClearLink (link_t *l);
+void RemoveLink (link_t *l);
+void InsertLinkBefore (link_t *l, link_t *before);
+void InsertLinkAfter (link_t *l, link_t *after);
+
+// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
+// ent = STRUCT_FROM_LINK(link,entity_t,order)
+// FIXME: remove this mess!
+#define	STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))
+
+//============================================================================
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define Q_MAXCHAR ((char)0x7f)
+#define Q_MAXSHORT ((short)0x7fff)
+#define Q_MAXINT	((int)0x7fffffff)
+#define Q_MAXLONG ((int)0x7fffffff)
+#define Q_MAXFLOAT ((int)0x7fffffff)
+
+#define Q_MINCHAR ((char)0x80)
+#define Q_MINSHORT ((short)0x8000)
+#define Q_MININT 	((int)0x80000000)
+#define Q_MINLONG ((int)0x80000000)
+#define Q_MINFLOAT ((int)0x7fffffff)
+
+//============================================================================
+
+extern	qboolean		bigendien;
+
+extern	short	(*BigShort) (short l);
+extern	short	(*LittleShort) (short l);
+extern	int	(*BigLong) (int l);
+extern	int	(*LittleLong) (int l);
+extern	float	(*BigFloat) (float l);
+extern	float	(*LittleFloat) (float l);
+
+//============================================================================
+
+void MSG_WriteChar (sizebuf_t *sb, int c);
+void MSG_WriteByte (sizebuf_t *sb, int c);
+void MSG_WriteShort (sizebuf_t *sb, int c);
+void MSG_WriteLong (sizebuf_t *sb, int c);
+void MSG_WriteFloat (sizebuf_t *sb, float f);
+void MSG_WriteString (sizebuf_t *sb, const char *s);
+void MSG_WriteCoord (sizebuf_t *sb, float f);
+void MSG_WriteAngle (sizebuf_t *sb, float f);
+
+extern	int			msg_readcount;
+extern	qboolean	msg_badread;		// set if a read goes beyond end of message
+
+void MSG_BeginReading (void);
+int MSG_ReadChar (void);
+int MSG_ReadByte (void);
+int MSG_ReadShort (void);
+int MSG_ReadLong (void);
+float MSG_ReadFloat (void);
+char *MSG_ReadString (void);
+
+float MSG_ReadCoord (void);
+float MSG_ReadAngle (void);
+
+//============================================================================
+
+void Q_memset (void *dest, int fill, int count);
+void Q_memcpy (void *dest, const void *src, int count);
+int Q_memcmp (const void *m1, const void *m2, int count);
+void Q_strcpy (char *dest, const char *src);
+void Q_strncpy (char *dest, const char *src, int count);
+int Q_strlen (const char *str);
+char *Q_strrchr (const char *s, char c);
+void Q_strcat (char *dest, const char *src);
+int Q_strcmp (const char *s1, const char *s2);
+int Q_strncmp (const char *s1, const char *s2, int count);
+int Q_strcasecmp (const char *s1, const char *s2);
+int Q_strncasecmp (const char *s1, const char *s2, int n);
+int	Q_atoi (const char *str);
+float Q_atof (const char *str);
+
+//============================================================================
+
+extern	char		com_token[1024];
+extern	qboolean	com_eof;
+
+char *COM_Parse (char *data);
+
+
+extern	int		com_argc;
+extern	const char	**com_argv;
+
+int COM_CheckParm (const char *parm);
+void COM_Init (const char *path);
+void COM_InitArgv (int argc, const char **argv);
+
+const char *COM_SkipPath (const char *pathname);
+void COM_StripExtension (const char *in, char *out);
+void COM_FileBase (const char *in, char *out, size_t outLength);
+void COM_DefaultExtension (char *path, const char *extension);
+
+char	*va(const char *format, ...);
+// does a varargs printf into a temp buffer
+
+
+//============================================================================
+
+extern int com_filesize;
+struct cache_user_s;
+
+extern	char	com_gamedir[MAX_OSPATH];
+
+void COM_WriteFile (const char *filename, void *data, int len);
+int COM_OpenFile (const char *filename, int *hndl);
+int COM_FOpenFile (const char *filename, FILE **file);
+void COM_CloseFile (int h);
+
+byte *COM_LoadStackFile (const char *path, void *buffer, int bufsize);
+byte *COM_LoadTempFile (const char *path);
+byte *COM_LoadHunkFile (const char *path);
+void COM_LoadCacheFile (const char *path, struct cache_user_s *cu);
+
+
+extern	struct cvar_s	registered;
+
+extern qboolean		standard_quake, rogue, hipnotic;
diff --git a/quake/src/WinQuake/conproc.c b/quake/src/WinQuake/conproc.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/conproc.c
rename to quake/src/WinQuake/conproc.cpp
diff --git a/quake/src/WinQuake/console.c b/quake/src/WinQuake/console.cpp
old mode 100644
new mode 100755
similarity index 94%
rename from quake/src/WinQuake/console.c
rename to quake/src/WinQuake/console.cpp
index 345519a..9ece41c
--- a/quake/src/WinQuake/console.c
+++ b/quake/src/WinQuake/console.cpp
@@ -1,649 +1,656 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// console.c

-

-#ifdef NeXT

-#include <libc.h>

-#endif

-#ifndef _MSC_VER

-#include <unistd.h>

-#endif

-#include <fcntl.h>

-#include "quakedef.h"

-

-int 		con_linewidth;

-

-float		con_cursorspeed = 4;

-

-#define		CON_TEXTSIZE	16384

-

-qboolean 	con_forcedup;		// because no entities to refresh

-

-int			con_totallines;		// total lines in console scrollback

-int			con_backscroll;		// lines up from bottom to display

-int			con_current;		// where next message will be printed

-int			con_x;				// offset in current line for next print

-char		*con_text=0;

-

-cvar_t		con_notifytime = {"con_notifytime","3"};		//seconds

-

-#define	NUM_CON_TIMES 4

-float		con_times[NUM_CON_TIMES];	// realtime time the line was generated

-								// for transparent notify lines

-

-int			con_vislines;

-

-qboolean	con_debuglog;

-

-#define		MAXCMDLINE	256

-extern	char	key_lines[32][MAXCMDLINE];

-extern	int		edit_line;

-extern	int		key_linepos;

-		

-

-qboolean	con_initialized;

-

-int			con_notifylines;		// scan lines to clear for notify lines

-

-extern void M_Menu_Main_f (void);

-

-/*

-================

-Con_ToggleConsole_f

-================

-*/

-void Con_ToggleConsole_f (void)

-{

-	if (key_dest == key_console)

-	{

-		if (cls.state == ca_connected)

-		{

-			key_dest = key_game;

-			key_lines[edit_line][1] = 0;	// clear any typing

-			key_linepos = 1;

-		}

-		else

-		{

-			M_Menu_Main_f ();

-		}

-	}

-	else

-		key_dest = key_console;

-	

-	SCR_EndLoadingPlaque ();

-	memset (con_times, 0, sizeof(con_times));

-}

-

-/*

-================

-Con_Clear_f

-================

-*/

-void Con_Clear_f (void)

-{

-	if (con_text)

-		Q_memset (con_text, ' ', CON_TEXTSIZE);

-}

-

-						

-/*

-================

-Con_ClearNotify

-================

-*/

-void Con_ClearNotify (void)

-{

-	int		i;

-	

-	for (i=0 ; i<NUM_CON_TIMES ; i++)

-		con_times[i] = 0;

-}

-

-						

-/*

-================

-Con_MessageMode_f

-================

-*/

-extern qboolean team_message;

-

-void Con_MessageMode_f (void)

-{

-	key_dest = key_message;

-	team_message = false;

-}

-

-						

-/*

-================

-Con_MessageMode2_f

-================

-*/

-void Con_MessageMode2_f (void)

-{

-	key_dest = key_message;

-	team_message = true;

-}

-

-						

-/*

-================

-Con_CheckResize

-

-If the line width has changed, reformat the buffer.

-================

-*/

-void Con_CheckResize (void)

-{

-	int		i, j, width, oldwidth, oldtotallines, numlines, numchars;

-	char	tbuf[CON_TEXTSIZE];

-

-	width = (vid.width >> 3) - 2;

-

-	if (width == con_linewidth)

-		return;

-

-	if (width < 1)			// video hasn't been initialized yet

-	{

-		width = 38;

-		con_linewidth = width;

-		con_totallines = CON_TEXTSIZE / con_linewidth;

-		Q_memset (con_text, ' ', CON_TEXTSIZE);

-	}

-	else

-	{

-		oldwidth = con_linewidth;

-		con_linewidth = width;

-		oldtotallines = con_totallines;

-		con_totallines = CON_TEXTSIZE / con_linewidth;

-		numlines = oldtotallines;

-

-		if (con_totallines < numlines)

-			numlines = con_totallines;

-

-		numchars = oldwidth;

-	

-		if (con_linewidth < numchars)

-			numchars = con_linewidth;

-

-		Q_memcpy (tbuf, con_text, CON_TEXTSIZE);

-		Q_memset (con_text, ' ', CON_TEXTSIZE);

-

-		for (i=0 ; i<numlines ; i++)

-		{

-			for (j=0 ; j<numchars ; j++)

-			{

-				con_text[(con_totallines - 1 - i) * con_linewidth + j] =

-						tbuf[((con_current - i + oldtotallines) %

-							  oldtotallines) * oldwidth + j];

-			}

-		}

-

-		Con_ClearNotify ();

-	}

-

-	con_backscroll = 0;

-	con_current = con_totallines - 1;

-}

-

-

-/*

-================

-Con_Init

-================

-*/

-void Con_Init (void)

-{

-#define MAXGAMEDIRLEN	1000

-	char	temp[MAXGAMEDIRLEN+1];

-	char	*t2 = "/qconsole.log";

-

-	con_debuglog = COM_CheckParm("-condebug");

-

-	if (con_debuglog)

-	{

-		if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))

-		{

-			sprintf (temp, "%s%s", com_gamedir, t2);

-			unlink (temp);

-		}

-	}

-

-	con_text = Hunk_AllocName (CON_TEXTSIZE, "context");

-	Q_memset (con_text, ' ', CON_TEXTSIZE);

-	con_linewidth = -1;

-	Con_CheckResize ();

-	

-	Con_Printf ("Console initialized.\n");

-

-//

-// register our commands

-//

-	Cvar_RegisterVariable (&con_notifytime);

-

-	Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);

-	Cmd_AddCommand ("messagemode", Con_MessageMode_f);

-	Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);

-	Cmd_AddCommand ("clear", Con_Clear_f);

-	con_initialized = true;

-}

-

-

-/*

-===============

-Con_Linefeed

-===============

-*/

-void Con_Linefeed (void)

-{

-	con_x = 0;

-	con_current++;

-	Q_memset (&con_text[(con_current%con_totallines)*con_linewidth]

-	, ' ', con_linewidth);

-}

-

-/*

-================

-Con_Print

-

-Handles cursor positioning, line wrapping, etc

-All console printing must go through this in order to be logged to disk

-If no console is visible, the notify window will pop up.

-================

-*/

-void Con_Print (char *txt)

-{

-	int		y;

-	int		c, l;

-	static int	cr;

-	int		mask;

-	

-	con_backscroll = 0;

-

-	if (txt[0] == 1)

-	{

-		mask = 128;		// go to colored text

-		S_LocalSound ("misc/talk.wav");

-	// play talk wav

-		txt++;

-	}

-	else if (txt[0] == 2)

-	{

-		mask = 128;		// go to colored text

-		txt++;

-	}

-	else

-		mask = 0;

-

-

-	while ( (c = *txt) )

-	{

-	// count word length

-		for (l=0 ; l< con_linewidth ; l++)

-			if ( txt[l] <= ' ')

-				break;

-

-	// word wrap

-		if (l != con_linewidth && (con_x + l > con_linewidth) )

-			con_x = 0;

-

-		txt++;

-

-		if (cr)

-		{

-			con_current--;

-			cr = false;

-		}

-

-		

-		if (!con_x)

-		{

-			Con_Linefeed ();

-		// mark time for transparent overlay

-			if (con_current >= 0)

-				con_times[con_current % NUM_CON_TIMES] = realtime;

-		}

-

-		switch (c)

-		{

-		case '\n':

-			con_x = 0;

-			break;

-

-		case '\r':

-			con_x = 0;

-			cr = 1;

-			break;

-

-		default:	// display character and advance

-			y = con_current % con_totallines;

-			con_text[y*con_linewidth+con_x] = c | mask;

-			con_x++;

-			if (con_x >= con_linewidth)

-				con_x = 0;

-			break;

-		}

-		

-	}

-}

-

-

-/*

-================

-Con_DebugLog

-================

-*/

-void Con_DebugLog(char *file, char *fmt, ...)

-{

-    va_list argptr; 

-    static char data[1024];

-    int fd;

-    

-    va_start(argptr, fmt);

-    vsprintf(data, fmt, argptr);

-    va_end(argptr);

-    fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);

-    write(fd, data, strlen(data));

-    close(fd);

-}

-

-

-/*

-================

-Con_Printf

-

-Handles cursor positioning, line wrapping, etc

-================

-*/

-#define	MAXPRINTMSG	4096

-// FIXME: make a buffer size safe vsprintf?

-void Con_Printf (char *fmt, ...)

-{

-	va_list		argptr;

-	char		msg[MAXPRINTMSG];

-	static qboolean	inupdate;

-	

-	va_start (argptr,fmt);

-	vsprintf (msg,fmt,argptr);

-	va_end (argptr);

-	

-// also echo to debugging console

-	Sys_Printf ("%s", msg);	// also echo to debugging console

-

-// log all messages to file

-	if (con_debuglog)

-		Con_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg);

-

-	if (!con_initialized)

-		return;

-		

-	if (cls.state == ca_dedicated)

-		return;		// no graphics mode

-

-// write it to the scrollable buffer

-	Con_Print (msg);

-	

-// update the screen if the console is displayed

-	if (cls.signon != SIGNONS && !scr_disabled_for_loading )

-	{

-	// protect against infinite loop if something in SCR_UpdateScreen calls

-	// Con_Printd

-		if (!inupdate)

-		{

-			inupdate = true;

-			SCR_UpdateScreen ();

-			inupdate = false;

-		}

-	}

-}

-

-/*

-================

-Con_DPrintf

-

-A Con_Printf that only shows up if the "developer" cvar is set

-================

-*/

-void Con_DPrintf (char *fmt, ...)

-{

-	va_list		argptr;

-	char		msg[MAXPRINTMSG];

-		

-	if (!developer.value)

-		return;			// don't confuse non-developers with techie stuff...

-

-	va_start (argptr,fmt);

-	vsprintf (msg,fmt,argptr);

-	va_end (argptr);

-	

-	Con_Printf ("%s", msg);

-}

-

-

-/*

-==================

-Con_SafePrintf

-

-Okay to call even when the screen can't be updated

-==================

-*/

-void Con_SafePrintf (char *fmt, ...)

-{

-	va_list		argptr;

-	char		msg[1024];

-	int			temp;

-		

-	va_start (argptr,fmt);

-	vsprintf (msg,fmt,argptr);

-	va_end (argptr);

-

-	temp = scr_disabled_for_loading;

-	scr_disabled_for_loading = true;

-	Con_Printf ("%s", msg);

-	scr_disabled_for_loading = temp;

-}

-

-

-/*

-==============================================================================

-

-DRAWING

-

-==============================================================================

-*/

-

-

-/*

-================

-Con_DrawInput

-

-The input line scrolls horizontally if typing goes beyond the right edge

-================

-*/

-void Con_DrawInput (void)

-{

-	int		y;

-	int		i;

-	char	*text;

-

-	if (key_dest != key_console && !con_forcedup)

-		return;		// don't draw anything

-

-	text = key_lines[edit_line];

-	

-// add the cursor frame

-	text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);

-	

-// fill out remainder with spaces

-	for (i=key_linepos+1 ; i< con_linewidth ; i++)

-		text[i] = ' ';

-		

-//	prestep if horizontally scrolling

-	if (key_linepos >= con_linewidth)

-		text += 1 + key_linepos - con_linewidth;

-		

-// draw it

-	y = con_vislines-16;

-

-	for (i=0 ; i<con_linewidth ; i++)

-		Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]);

-

-// remove cursor

-	key_lines[edit_line][key_linepos] = 0;

-}

-

-

-/*

-================

-Con_DrawNotify

-

-Draws the last few lines of output transparently over the game top

-================

-*/

-void Con_DrawNotify (void)

-{

-	int		x, v;

-	char	*text;

-	int		i;

-	float	time;

-	extern char chat_buffer[];

-

-	v = 0;

-	for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++)

-	{

-		if (i < 0)

-			continue;

-		time = con_times[i % NUM_CON_TIMES];

-		if (time == 0)

-			continue;

-		time = realtime - time;

-		if (time > con_notifytime.value)

-			continue;

-		text = con_text + (i % con_totallines)*con_linewidth;

-		

-		clearnotify = 0;

-		scr_copytop = 1;

-

-		for (x = 0 ; x < con_linewidth ; x++)

-			Draw_Character ( (x+1)<<3, v, text[x]);

-

-		v += 8;

-	}

-

-

-	if (key_dest == key_message)

-	{

-		clearnotify = 0;

-		scr_copytop = 1;

-	

-		x = 0;

-		

-		Draw_String (8, v, "say:");

-		while(chat_buffer[x])

-		{

-			Draw_Character ( (x+5)<<3, v, chat_buffer[x]);

-			x++;

-		}

-		Draw_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));

-		v += 8;

-	}

-	

-	if (v > con_notifylines)

-		con_notifylines = v;

-}

-

-/*

-================

-Con_DrawConsole

-

-Draws the console with the solid background

-The typing input line at the bottom should only be drawn if typing is allowed

-================

-*/

-void Con_DrawConsole (int lines, qboolean drawinput)

-{

-	int				i, x, y;

-	int				rows;

-	char			*text;

-	int				j;

-	

-	if (lines <= 0)

-		return;

-

-// draw the background

-	Draw_ConsoleBackground (lines);

-

-// draw the text

-	con_vislines = lines;

-

-	rows = (lines-16)>>3;		// rows of text to draw

-	y = lines - 16 - (rows<<3);	// may start slightly negative

-

-	for (i= con_current - rows + 1 ; i<=con_current ; i++, y+=8 )

-	{

-		j = i - con_backscroll;

-		if (j<0)

-			j = 0;

-		text = con_text + (j % con_totallines)*con_linewidth;

-

-		for (x=0 ; x<con_linewidth ; x++)

-			Draw_Character ( (x+1)<<3, y, text[x]);

-	}

-

-// draw the input prompt, user text, and cursor if desired

-	if (drawinput)

-		Con_DrawInput ();

-}

-

-

-/*

-==================

-Con_NotifyBox

-==================

-*/

-void Con_NotifyBox (char *text)

-{

-	double		t1, t2;

-

-// during startup for sound / cd warnings

-	Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");

-

-	Con_Printf (text);

-

-	Con_Printf ("Press a key.\n");

-	Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");

-

-	key_count = -2;		// wait for a key down and up

-	key_dest = key_console;

-

-	do

-	{

-		t1 = Sys_FloatTime ();

-		SCR_UpdateScreen ();

-		Sys_SendKeyEvents ();

-		t2 = Sys_FloatTime ();

-		realtime += t2-t1;		// make the cursor blink

-	} while (key_count < 0);

-

-	Con_Printf ("\n");

-	key_dest = key_game;

-	realtime = 0;				// put the cursor back to invisible

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// console.c
+
+#ifdef NeXT
+#include <libc.h>
+#endif
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include "quakedef.h"
+
+int 		con_linewidth;
+
+float		con_cursorspeed = 4;
+
+#define		CON_TEXTSIZE	16384
+
+qboolean 	con_forcedup;		// because no entities to refresh
+
+int			con_totallines;		// total lines in console scrollback
+int			con_backscroll;		// lines up from bottom to display
+int			con_current;		// where next message will be printed
+int			con_x;				// offset in current line for next print
+char		*con_text=0;
+
+cvar_t		con_notifytime = CVAR2("con_notifytime","3");		//seconds
+
+#define	NUM_CON_TIMES 4
+float		con_times[NUM_CON_TIMES];	// realtime time the line was generated
+								// for transparent notify lines
+
+int			con_vislines;
+
+qboolean	con_debuglog;
+
+#define		MAXCMDLINE	256
+extern	char	key_lines[32][MAXCMDLINE];
+extern	int		edit_line;
+extern	int		key_linepos;
+		
+
+qboolean	con_initialized;
+
+int			con_notifylines;		// scan lines to clear for notify lines
+
+extern void M_Menu_Main_f (void);
+
+/*
+================
+Con_ToggleConsole_f
+================
+*/
+void Con_ToggleConsole_f (void)
+{
+	if (key_dest == key_console)
+	{
+		if (cls.state == ca_connected)
+		{
+			key_dest = key_game;
+			key_lines[edit_line][1] = 0;	// clear any typing
+			key_linepos = 1;
+		}
+		else
+		{
+			M_Menu_Main_f ();
+		}
+	}
+	else
+		key_dest = key_console;
+	
+	SCR_EndLoadingPlaque ();
+	memset (con_times, 0, sizeof(con_times));
+}
+
+/*
+================
+Con_Clear_f
+================
+*/
+void Con_Clear_f (void)
+{
+	if (con_text)
+		Q_memset (con_text, ' ', CON_TEXTSIZE);
+}
+
+						
+/*
+================
+Con_ClearNotify
+================
+*/
+void Con_ClearNotify (void)
+{
+	int		i;
+	
+	for (i=0 ; i<NUM_CON_TIMES ; i++)
+		con_times[i] = 0;
+}
+
+						
+/*
+================
+Con_MessageMode_f
+================
+*/
+extern qboolean team_message;
+
+void Con_MessageMode_f (void)
+{
+	key_dest = key_message;
+	team_message = false;
+}
+
+						
+/*
+================
+Con_MessageMode2_f
+================
+*/
+void Con_MessageMode2_f (void)
+{
+	key_dest = key_message;
+	team_message = true;
+}
+
+						
+/*
+================
+Con_CheckResize
+
+If the line width has changed, reformat the buffer.
+================
+*/
+void Con_CheckResize (void)
+{
+	int		i, j, width, oldwidth, oldtotallines, numlines, numchars;
+	char	tbuf[CON_TEXTSIZE];
+
+	width = (vid.width >> 3) - 2;
+
+	if (width == con_linewidth)
+		return;
+
+	if (width < 1)			// video hasn't been initialized yet
+	{
+		width = 38;
+		con_linewidth = width;
+		con_totallines = CON_TEXTSIZE / con_linewidth;
+		Q_memset (con_text, ' ', CON_TEXTSIZE);
+	}
+	else
+	{
+		oldwidth = con_linewidth;
+		con_linewidth = width;
+		oldtotallines = con_totallines;
+		con_totallines = CON_TEXTSIZE / con_linewidth;
+		numlines = oldtotallines;
+
+		if (con_totallines < numlines)
+			numlines = con_totallines;
+
+		numchars = oldwidth;
+	
+		if (con_linewidth < numchars)
+			numchars = con_linewidth;
+
+		Q_memcpy (tbuf, con_text, CON_TEXTSIZE);
+		Q_memset (con_text, ' ', CON_TEXTSIZE);
+
+		for (i=0 ; i<numlines ; i++)
+		{
+			for (j=0 ; j<numchars ; j++)
+			{
+				con_text[(con_totallines - 1 - i) * con_linewidth + j] =
+						tbuf[((con_current - i + oldtotallines) %
+							  oldtotallines) * oldwidth + j];
+			}
+		}
+
+		Con_ClearNotify ();
+	}
+
+	con_backscroll = 0;
+	con_current = con_totallines - 1;
+}
+
+
+/*
+================
+Con_Init
+================
+*/
+void Con_Init (void)
+{
+#define MAXGAMEDIRLEN	1000
+	char	temp[MAXGAMEDIRLEN+1];
+	const char	*t2 = "/qconsole.log";
+
+	con_debuglog = COM_CheckParm("-condebug");
+
+	if (con_debuglog)
+	{
+		if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
+		{
+			sprintf (temp, "%s%s", com_gamedir, t2);
+			unlink (temp);
+		}
+	}
+
+	con_text = (char*) Hunk_AllocName (CON_TEXTSIZE, "context");
+	Q_memset (con_text, ' ', CON_TEXTSIZE);
+	con_linewidth = -1;
+	Con_CheckResize ();
+	
+	Con_Printf ("Console initialized.\n");
+
+//
+// register our commands
+//
+	Cvar_RegisterVariable (&con_notifytime);
+
+	Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
+	Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+	Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+	Cmd_AddCommand ("clear", Con_Clear_f);
+	con_initialized = true;
+}
+
+
+/*
+===============
+Con_Linefeed
+===============
+*/
+void Con_Linefeed (void)
+{
+	con_x = 0;
+	con_current++;
+	Q_memset (&con_text[(con_current%con_totallines)*con_linewidth]
+	, ' ', con_linewidth);
+}
+
+/*
+================
+Con_Print
+
+Handles cursor positioning, line wrapping, etc
+All console printing must go through this in order to be logged to disk
+If no console is visible, the notify window will pop up.
+================
+*/
+void Con_Print (const char *txt)
+{
+	int		y;
+	int		c, l;
+	static int	cr;
+	int		mask;
+	
+	con_backscroll = 0;
+
+	if (txt[0] == 1)
+	{
+		mask = 128;		// go to colored text
+		S_LocalSound ("misc/talk.wav");
+	// play talk wav
+		txt++;
+	}
+	else if (txt[0] == 2)
+	{
+		mask = 128;		// go to colored text
+		txt++;
+	}
+	else
+		mask = 0;
+
+
+	while ( (c = *txt) )
+	{
+	// count word length
+		for (l=0 ; l< con_linewidth ; l++)
+			if ( txt[l] <= ' ')
+				break;
+
+	// word wrap
+		if (l != con_linewidth && (con_x + l > con_linewidth) )
+			con_x = 0;
+
+		txt++;
+
+		if (cr)
+		{
+			con_current--;
+			cr = false;
+		}
+
+		
+		if (!con_x)
+		{
+			Con_Linefeed ();
+		// mark time for transparent overlay
+			if (con_current >= 0)
+				con_times[con_current % NUM_CON_TIMES] = realtime;
+		}
+
+		switch (c)
+		{
+		case '\n':
+			con_x = 0;
+			break;
+
+		case '\r':
+			con_x = 0;
+			cr = 1;
+			break;
+
+		default:	// display character and advance
+			y = con_current % con_totallines;
+			con_text[y*con_linewidth+con_x] = c | mask;
+			con_x++;
+			if (con_x >= con_linewidth)
+				con_x = 0;
+			break;
+		}
+		
+	}
+}
+
+
+/*
+================
+Con_DebugLog
+================
+*/
+void Con_DebugLog(const char *file, const char *fmt, ...)
+{
+    va_list argptr; 
+    static char data[1024];
+    int fd;
+    
+    va_start(argptr, fmt);
+    vsprintf(data, fmt, argptr);
+    va_end(argptr);
+    fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
+    write(fd, data, strlen(data));
+    close(fd);
+}
+
+
+/*
+================
+Con_Printf
+
+Handles cursor positioning, line wrapping, etc
+================
+*/
+#define	MAXPRINTMSG	4096
+// FIXME: make a buffer size safe vsprintf?
+void Con_Printf (const char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+	static qboolean	inupdate;
+	
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+	
+// also echo to debugging console
+	Sys_Printf ("%s", msg);	// also echo to debugging console
+
+// log all messages to file
+	if (con_debuglog)
+		Con_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg);
+
+	if (!con_initialized)
+		return;
+		
+	if (cls.state == ca_dedicated)
+		return;		// no graphics mode
+
+// write it to the scrollable buffer
+	Con_Print (msg);
+	
+// update the screen if the console is displayed
+	if (cls.signon != SIGNONS && !scr_disabled_for_loading )
+	{
+	// protect against infinite loop if something in SCR_UpdateScreen calls
+	// Con_Printd
+		if (!inupdate)
+		{
+			inupdate = true;
+			SCR_UpdateScreen ();
+			inupdate = false;
+		}
+	}
+}
+
+/*
+================
+Con_DPrintf
+
+A Con_Printf that only shows up if the "developer" cvar is set
+================
+*/
+void Con_DPrintf (const char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[MAXPRINTMSG];
+		
+	if (!developer.value)
+		return;			// don't confuse non-developers with techie stuff...
+
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+	
+	Con_Printf ("%s", msg);
+}
+
+
+/*
+==================
+Con_SafePrintf
+
+Okay to call even when the screen can't be updated
+==================
+*/
+void Con_SafePrintf (const char *fmt, ...)
+{
+	va_list		argptr;
+	char		msg[1024];
+	int			temp;
+		
+	va_start (argptr,fmt);
+	vsprintf (msg,fmt,argptr);
+	va_end (argptr);
+
+	temp = scr_disabled_for_loading;
+	scr_disabled_for_loading = true;
+	Con_Printf ("%s", msg);
+	scr_disabled_for_loading = temp;
+}
+
+
+/*
+==============================================================================
+
+DRAWING
+
+==============================================================================
+*/
+
+
+/*
+================
+Con_DrawInput
+
+The input line scrolls horizontally if typing goes beyond the right edge
+================
+*/
+void Con_DrawInput (void)
+{
+	int		y;
+	int		i;
+	char	*text;
+
+	if (key_dest != key_console && !con_forcedup)
+		return;		// don't draw anything
+
+	text = key_lines[edit_line];
+	
+// add the cursor frame
+	text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);
+	
+// fill out remainder with spaces
+	for (i=key_linepos+1 ; i< con_linewidth ; i++)
+		text[i] = ' ';
+		
+//	prestep if horizontally scrolling
+	if (key_linepos >= con_linewidth)
+		text += 1 + key_linepos - con_linewidth;
+		
+// draw it
+	y = con_vislines-16;
+
+	for (i=0 ; i<con_linewidth ; i++)
+		Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]);
+
+// remove cursor
+	key_lines[edit_line][key_linepos] = 0;
+}
+
+
+/*
+================
+Con_DrawNotify
+
+Draws the last few lines of output transparently over the game top
+================
+*/
+void Con_DrawNotify (void)
+{
+	int		x, v;
+	char	*text;
+	int		i;
+	float	time;
+	extern char chat_buffer[];
+
+	v = 0;
+	for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++)
+	{
+		if (i < 0)
+			continue;
+		time = con_times[i % NUM_CON_TIMES];
+		if (time == 0)
+			continue;
+		time = realtime - time;
+		if (time > con_notifytime.value)
+			continue;
+		text = con_text + (i % con_totallines)*con_linewidth;
+		
+		clearnotify = 0;
+		scr_copytop = 1;
+
+		for (x = 0 ; x < con_linewidth ; x++)
+			Draw_Character ( (x+1)<<3, v, text[x]);
+
+		v += 8;
+	}
+
+
+	if (key_dest == key_message)
+	{
+		clearnotify = 0;
+		scr_copytop = 1;
+	
+		x = 0;
+		
+		Draw_String (8, v, "say:");
+		while(chat_buffer[x])
+		{
+			Draw_Character ( (x+5)<<3, v, chat_buffer[x]);
+			x++;
+		}
+		Draw_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));
+		v += 8;
+	}
+	
+	if (v > con_notifylines)
+		con_notifylines = v;
+}
+
+/*
+================
+Con_DrawConsole
+
+Draws the console with the solid background
+The typing input line at the bottom should only be drawn if typing is allowed
+================
+*/
+void Con_DrawConsole (int lines, qboolean drawinput)
+{
+	int				i, x, y;
+	int				rows;
+	char			*text;
+	int				j;
+	
+	if (lines <= 0)
+		return;
+
+#ifdef USE_OPENGLES
+	// Don't draw console during time demo, it skews the timedemo
+	// statistics too much towards optimizing console drawing.
+	if(cls.timedemo)
+		return;
+#endif
+
+// draw the background
+	Draw_ConsoleBackground (lines);
+
+// draw the text
+	con_vislines = lines;
+
+	rows = (lines-16)>>3;		// rows of text to draw
+	y = lines - 16 - (rows<<3);	// may start slightly negative
+
+	for (i= con_current - rows + 1 ; i<=con_current ; i++, y+=8 )
+	{
+		j = i - con_backscroll;
+		if (j<0)
+			j = 0;
+		text = con_text + (j % con_totallines)*con_linewidth;
+
+		for (x=0 ; x<con_linewidth ; x++)
+			Draw_Character ( (x+1)<<3, y, text[x]);
+	}
+
+// draw the input prompt, user text, and cursor if desired
+	if (drawinput)
+		Con_DrawInput ();
+}
+
+
+/*
+==================
+Con_NotifyBox
+==================
+*/
+void Con_NotifyBox (const char *text)
+{
+	double		t1, t2;
+
+// during startup for sound / cd warnings
+	Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");
+
+	Con_Printf (text);
+
+	Con_Printf ("Press a key.\n");
+	Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");
+
+	key_count = -2;		// wait for a key down and up
+	key_dest = key_console;
+
+	do
+	{
+		t1 = Sys_FloatTime ();
+		SCR_UpdateScreen ();
+		Sys_SendKeyEvents ();
+		t2 = Sys_FloatTime ();
+		realtime += t2-t1;		// make the cursor blink
+	} while (key_count < 0);
+
+	Con_Printf ("\n");
+	key_dest = key_game;
+	realtime = 0;				// put the cursor back to invisible
+}
+
diff --git a/quake/src/WinQuake/console.h b/quake/src/WinQuake/console.h
index 1601c98..6fdfb6c 100644
--- a/quake/src/WinQuake/console.h
+++ b/quake/src/WinQuake/console.h
@@ -1,46 +1,46 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-//

-// console

-//

-extern int con_totallines;

-extern int con_backscroll;

-extern	qboolean con_forcedup;	// because no entities to refresh

-extern qboolean con_initialized;

-extern byte *con_chars;

-extern	int	con_notifylines;		// scan lines to clear for notify lines

-

-void Con_DrawCharacter (int cx, int line, int num);

-

-void Con_CheckResize (void);

-void Con_Init (void);

-void Con_DrawConsole (int lines, qboolean drawinput);

-void Con_Print (char *txt);

-void Con_Printf (char *fmt, ...);

-void Con_DPrintf (char *fmt, ...);

-void Con_SafePrintf (char *fmt, ...);

-void Con_Clear_f (void);

-void Con_DrawNotify (void);

-void Con_ClearNotify (void);

-void Con_ToggleConsole_f (void);

-

-void Con_NotifyBox (char *text);	// during startup for sound / cd warnings

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+//
+// console
+//
+extern int con_totallines;
+extern int con_backscroll;
+extern	qboolean con_forcedup;	// because no entities to refresh
+extern qboolean con_initialized;
+extern byte *con_chars;
+extern	int	con_notifylines;		// scan lines to clear for notify lines
+
+void Con_DrawCharacter (int cx, int line, int num);
+
+void Con_CheckResize (void);
+void Con_Init (void);
+void Con_DrawConsole (int lines, qboolean drawinput);
+void Con_Print (const char *txt);
+void Con_Printf (const char *fmt, ...);
+void Con_DPrintf (const char *fmt, ...);
+void Con_SafePrintf (const char *fmt, ...);
+void Con_Clear_f (void);
+void Con_DrawNotify (void);
+void Con_ClearNotify (void);
+void Con_ToggleConsole_f (void);
+
+void Con_NotifyBox (const char *text);	// during startup for sound / cd warnings
+
diff --git a/quake/src/WinQuake/crc.c b/quake/src/WinQuake/crc.cpp
old mode 100644
new mode 100755
similarity index 99%
rename from quake/src/WinQuake/crc.c
rename to quake/src/WinQuake/crc.cpp
index 847c3cc..5a12b3b
--- a/quake/src/WinQuake/crc.c
+++ b/quake/src/WinQuake/crc.cpp
@@ -78,4 +78,4 @@
 unsigned short CRC_Value(unsigned short crcvalue)

 {

 	return crcvalue ^ CRC_XOR_VALUE;

-}
\ No newline at end of file
+}

diff --git a/quake/src/WinQuake/cvar.c b/quake/src/WinQuake/cvar.cpp
old mode 100644
new mode 100755
similarity index 88%
rename from quake/src/WinQuake/cvar.c
rename to quake/src/WinQuake/cvar.cpp
index 18fb62e..04db94a
--- a/quake/src/WinQuake/cvar.c
+++ b/quake/src/WinQuake/cvar.cpp
@@ -1,224 +1,224 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// cvar.c -- dynamic variable tracking

-

-#include "quakedef.h"

-

-cvar_t	*cvar_vars;

-char	*cvar_null_string = "";

-

-/*

-============

-Cvar_FindVar

-============

-*/

-cvar_t *Cvar_FindVar (char *var_name)

-{

-	cvar_t	*var;

-	

-	for (var=cvar_vars ; var ; var=var->next)

-		if (!Q_strcmp (var_name, var->name))

-			return var;

-

-	return NULL;

-}

-

-/*

-============

-Cvar_VariableValue

-============

-*/

-float	Cvar_VariableValue (char *var_name)

-{

-	cvar_t	*var;

-	

-	var = Cvar_FindVar (var_name);

-	if (!var)

-		return 0;

-	return Q_atof (var->string);

-}

-

-

-/*

-============

-Cvar_VariableString

-============

-*/

-char *Cvar_VariableString (char *var_name)

-{

-	cvar_t *var;

-	

-	var = Cvar_FindVar (var_name);

-	if (!var)

-		return cvar_null_string;

-	return var->string;

-}

-

-

-/*

-============

-Cvar_CompleteVariable

-============

-*/

-char *Cvar_CompleteVariable (char *partial)

-{

-	cvar_t		*cvar;

-	int			len;

-	

-	len = Q_strlen(partial);

-	

-	if (!len)

-		return NULL;

-		

-// check functions

-	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)

-		if (!Q_strncmp (partial,cvar->name, len))

-			return cvar->name;

-

-	return NULL;

-}

-

-

-/*

-============

-Cvar_Set

-============

-*/

-void Cvar_Set (char *var_name, char *value)

-{

-	cvar_t	*var;

-	qboolean changed;

-	

-	var = Cvar_FindVar (var_name);

-	if (!var)

-	{	// there is an error in C code if this happens

-		Con_Printf ("Cvar_Set: variable %s not found\n", var_name);

-		return;

-	}

-

-	changed = Q_strcmp(var->string, value);

-	

-	Z_Free (var->string);	// free the old value string

-	

-	var->string = Z_Malloc (Q_strlen(value)+1);

-	Q_strcpy (var->string, value);

-	var->value = Q_atof (var->string);

-	if (var->server && changed)

-	{

-		if (sv.active)

-			SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string);

-	}

-}

-

-/*

-============

-Cvar_SetValue

-============

-*/

-void Cvar_SetValue (char *var_name, float value)

-{

-	char	val[32];

-	

-	sprintf (val, "%f",value);

-	Cvar_Set (var_name, val);

-}

-

-

-/*

-============

-Cvar_RegisterVariable

-

-Adds a freestanding variable to the variable list.

-============

-*/

-void Cvar_RegisterVariable (cvar_t *variable)

-{

-	char	*oldstr;

-	

-// first check to see if it has allready been defined

-	if (Cvar_FindVar (variable->name))

-	{

-		Con_Printf ("Can't register variable %s, allready defined\n", variable->name);

-		return;

-	}

-	

-// check for overlap with a command

-	if (Cmd_Exists (variable->name))

-	{

-		Con_Printf ("Cvar_RegisterVariable: %s is a command\n", variable->name);

-		return;

-	}

-		

-// copy the value off, because future sets will Z_Free it

-	oldstr = variable->string;

-	variable->string = Z_Malloc (Q_strlen(variable->string)+1);	

-	Q_strcpy (variable->string, oldstr);

-	variable->value = Q_atof (variable->string);

-	

-// link the variable in

-	variable->next = cvar_vars;

-	cvar_vars = variable;

-}

-

-/*

-============

-Cvar_Command

-

-Handles variable inspection and changing from the console

-============

-*/

-qboolean	Cvar_Command (void)

-{

-	cvar_t			*v;

-

-// check variables

-	v = Cvar_FindVar (Cmd_Argv(0));

-	if (!v)

-		return false;

-		

-// perform a variable print or set

-	if (Cmd_Argc() == 1)

-	{

-		Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);

-		return true;

-	}

-

-	Cvar_Set (v->name, Cmd_Argv(1));

-	return true;

-}

-

-

-/*

-============

-Cvar_WriteVariables

-

-Writes lines containing "set variable value" for all variables

-with the archive flag set to true.

-============

-*/

-void Cvar_WriteVariables (FILE *f)

-{

-	cvar_t	*var;

-	

-	for (var = cvar_vars ; var ; var = var->next)

-		if (var->archive)

-			fprintf (f, "%s \"%s\"\n", var->name, var->string);

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// cvar.c -- dynamic variable tracking
+
+#include "quakedef.h"
+
+cvar_t	*cvar_vars;
+const char	*cvar_null_string = "";
+
+/*
+============
+Cvar_FindVar
+============
+*/
+cvar_t *Cvar_FindVar (const char *var_name)
+{
+	cvar_t	*var;
+	
+	for (var=cvar_vars ; var ; var=var->next)
+		if (!Q_strcmp (var_name, var->name))
+			return var;
+
+	return NULL;
+}
+
+/*
+============
+Cvar_VariableValue
+============
+*/
+float	Cvar_VariableValue (const char *var_name)
+{
+	cvar_t	*var;
+	
+	var = Cvar_FindVar (var_name);
+	if (!var)
+		return 0;
+	return Q_atof (var->string);
+}
+
+
+/*
+============
+Cvar_VariableString
+============
+*/
+const char *Cvar_VariableString (const char *var_name)
+{
+	cvar_t *var;
+	
+	var = Cvar_FindVar (var_name);
+	if (!var)
+		return cvar_null_string;
+	return var->string;
+}
+
+
+/*
+============
+Cvar_CompleteVariable
+============
+*/
+const char *Cvar_CompleteVariable (const char *partial)
+{
+	cvar_t		*cvar;
+	int			len;
+	
+	len = Q_strlen(partial);
+	
+	if (!len)
+		return NULL;
+		
+// check functions
+	for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
+		if (!Q_strncmp (partial,cvar->name, len))
+			return cvar->name;
+
+	return NULL;
+}
+
+
+/*
+============
+Cvar_Set
+============
+*/
+void Cvar_Set (const char *var_name, const char *value)
+{
+	cvar_t	*var;
+	qboolean changed;
+	
+	var = Cvar_FindVar (var_name);
+	if (!var)
+	{	// there is an error in C code if this happens
+		Con_Printf ("Cvar_Set: variable %s not found\n", var_name);
+		return;
+	}
+
+	changed = Q_strcmp(var->string, value);
+	
+	Z_Free (var->string);	// free the old value string
+	
+	var->string = (char*) Z_Malloc (Q_strlen(value)+1);
+	Q_strcpy (var->string, value);
+	var->value = Q_atof (var->string);
+	if (var->server && changed)
+	{
+		if (sv.active)
+			SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string);
+	}
+}
+
+/*
+============
+Cvar_SetValue
+============
+*/
+void Cvar_SetValue (const char *var_name, float value)
+{
+	char	val[32];
+	
+	sprintf (val, "%f",value);
+	Cvar_Set (var_name, val);
+}
+
+
+/*
+============
+Cvar_RegisterVariable
+
+Adds a freestanding variable to the variable list.
+============
+*/
+void Cvar_RegisterVariable (cvar_t *variable)
+{
+	char	*oldstr;
+	
+// first check to see if it has allready been defined
+	if (Cvar_FindVar (variable->name))
+	{
+		Con_Printf ("Can't register variable %s, allready defined\n", variable->name);
+		return;
+	}
+	
+// check for overlap with a command
+	if (Cmd_Exists (variable->name))
+	{
+		Con_Printf ("Cvar_RegisterVariable: %s is a command\n", variable->name);
+		return;
+	}
+		
+// copy the value off, because future sets will Z_Free it
+	oldstr = variable->string;
+	variable->string = (char*) Z_Malloc (Q_strlen(variable->string)+1);	
+	Q_strcpy (variable->string, oldstr);
+	variable->value = Q_atof (variable->string);
+	
+// link the variable in
+	variable->next = cvar_vars;
+	cvar_vars = variable;
+}
+
+/*
+============
+Cvar_Command
+
+Handles variable inspection and changing from the console
+============
+*/
+qboolean	Cvar_Command (void)
+{
+	cvar_t			*v;
+
+// check variables
+	v = Cvar_FindVar (Cmd_Argv(0));
+	if (!v)
+		return false;
+		
+// perform a variable print or set
+	if (Cmd_Argc() == 1)
+	{
+		Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
+		return true;
+	}
+
+	Cvar_Set (v->name, Cmd_Argv(1));
+	return true;
+}
+
+
+/*
+============
+Cvar_WriteVariables
+
+Writes lines containing "set variable value" for all variables
+with the archive flag set to true.
+============
+*/
+void Cvar_WriteVariables (FILE *f)
+{
+	cvar_t	*var;
+	
+	for (var = cvar_vars ; var ; var = var->next)
+		if (var->archive)
+			fprintf (f, "%s \"%s\"\n", var->name, var->string);
+}
+
diff --git a/quake/src/WinQuake/cvar.h b/quake/src/WinQuake/cvar.h
index 771b340..71df90d 100644
--- a/quake/src/WinQuake/cvar.h
+++ b/quake/src/WinQuake/cvar.h
@@ -1,97 +1,102 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// cvar.h

-

-/*

-

-cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly

-in C code.

-

-it is sufficient to initialize a cvar_t with just the first two fields, or

-you can add a ,true flag for variables that you want saved to the configuration

-file when the game is quit:

-

-cvar_t	r_draworder = {"r_draworder","1"};

-cvar_t	scr_screensize = {"screensize","1",true};

-

-Cvars must be registered before use, or they will have a 0 value instead of the float interpretation of the string.  Generally, all cvar_t declarations should be registered in the apropriate init function before any console commands are executed:

-Cvar_RegisterVariable (&host_framerate);

-

-

-C code usually just references a cvar in place:

-if ( r_draworder.value )

-

-It could optionally ask for the value to be looked up for a string name:

-if (Cvar_VariableValue ("r_draworder"))

-

-Interpreted prog code can access cvars with the cvar(name) or

-cvar_set (name, value) internal functions:

-teamplay = cvar("teamplay");

-cvar_set ("registered", "1");

-

-The user can access cvars from the console in two ways:

-r_draworder			prints the current value

-r_draworder 0		sets the current value to 0

-Cvars are restricted from having the same names as commands to keep this

-interface from being ambiguous.

-*/

-

-typedef struct cvar_s

-{

-	char	*name;

-	char	*string;

-	qboolean archive;		// set to true to cause it to be saved to vars.rc

-	qboolean server;		// notifies players when changed

-	float	value;

-	struct cvar_s *next;

-} cvar_t;

-

-void 	Cvar_RegisterVariable (cvar_t *variable);

-// registers a cvar that allready has the name, string, and optionally the

-// archive elements set.

-

-void 	Cvar_Set (char *var_name, char *value);

-// equivelant to "<name> <variable>" typed at the console

-

-void	Cvar_SetValue (char *var_name, float value);

-// expands value to a string and calls Cvar_Set

-

-float	Cvar_VariableValue (char *var_name);

-// returns 0 if not defined or non numeric

-

-char	*Cvar_VariableString (char *var_name);

-// returns an empty string if not defined

-

-char 	*Cvar_CompleteVariable (char *partial);

-// attempts to match a partial variable name for command line completion

-// returns NULL if nothing fits

-

-qboolean Cvar_Command (void);

-// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known

-// command.  Returns true if the command was a variable reference that

-// was handled. (print or change)

-

-void 	Cvar_WriteVariables (FILE *f);

-// Writes lines containing "set variable value" for all variables

-// with the archive flag set to true.

-

-cvar_t *Cvar_FindVar (char *var_name);

-

-extern cvar_t	*cvar_vars;

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// cvar.h
+
+/*
+
+cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly
+in C code.
+
+it is sufficient to initialize a cvar_t with just the first two fields, or
+you can add a ,true flag for variables that you want saved to the configuration
+file when the game is quit:
+
+cvar_t	r_draworder = {"r_draworder","1"};
+cvar_t	scr_screensize = {"screensize","1",true};
+
+Cvars must be registered before use, or they will have a 0 value instead of the float interpretation of the string.  Generally, all cvar_t declarations should be registered in the apropriate init function before any console commands are executed:
+Cvar_RegisterVariable (&host_framerate);
+
+
+C code usually just references a cvar in place:
+if ( r_draworder.value )
+
+It could optionally ask for the value to be looked up for a string name:
+if (Cvar_VariableValue ("r_draworder"))
+
+Interpreted prog code can access cvars with the cvar(name) or
+cvar_set (name, value) internal functions:
+teamplay = cvar("teamplay");
+cvar_set ("registered", "1");
+
+The user can access cvars from the console in two ways:
+r_draworder			prints the current value
+r_draworder 0		sets the current value to 0
+Cvars are restricted from having the same names as commands to keep this
+interface from being ambiguous.
+*/
+
+typedef struct cvar_s
+{
+	char	*name;
+	char	*string;
+	qboolean archive;		// set to true to cause it to be saved to vars.rc
+	qboolean server;		// notifies players when changed
+	float	value;
+	struct cvar_s *next;
+} cvar_t;
+
+// Helper macro to avoid missing initializer warnings 
+#define CVAR2(NAME, STRING) {(char*) (NAME),(char*) (STRING), 0, 0, 0.0f, (struct cvar_s*) 0}
+#define CVAR3(NAME, STRING, ARCHIVE) {(char*) (NAME), (char*) (STRING), (ARCHIVE), 0, 0.0f, (struct cvar_s*) 0}
+#define CVAR4(NAME, STRING, ARCHIVE, INFO) {(char*) (NAME), (char*) (STRING), (ARCHIVE), (INFO), 0.0f, (struct cvar_s*) 0}
+
+void 	Cvar_RegisterVariable (cvar_t *variable);
+// registers a cvar that allready has the name, string, and optionally the
+// archive elements set.
+
+void 	Cvar_Set (const char *var_name, const char *value);
+// equivelant to "<name> <variable>" typed at the console
+
+void	Cvar_SetValue (const char *var_name, float value);
+// expands value to a string and calls Cvar_Set
+
+float	Cvar_VariableValue (const char *var_name);
+// returns 0 if not defined or non numeric
+
+const char	*Cvar_VariableString (const char *var_name);
+// returns an empty string if not defined
+
+const char 	*Cvar_CompleteVariable (const char *partial);
+// attempts to match a partial variable name for command line completion
+// returns NULL if nothing fits
+
+qboolean Cvar_Command (void);
+// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known
+// command.  Returns true if the command was a variable reference that
+// was handled. (print or change)
+
+void 	Cvar_WriteVariables (FILE *f);
+// Writes lines containing "set variable value" for all variables
+// with the archive flag set to true.
+
+cvar_t *Cvar_FindVar (const char *var_name);
+
+extern cvar_t	*cvar_vars;
diff --git a/quake/src/WinQuake/cwsdpmi.exe b/quake/src/WinQuake/cwsdpmi.exe
old mode 100755
new mode 100644
Binary files differ
diff --git a/quake/src/WinQuake/d_edge.c b/quake/src/WinQuake/d_edge.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_edge.c
rename to quake/src/WinQuake/d_edge.cpp
diff --git a/quake/src/WinQuake/d_fill.c b/quake/src/WinQuake/d_fill.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_fill.c
rename to quake/src/WinQuake/d_fill.cpp
diff --git a/quake/src/WinQuake/d_iface.h b/quake/src/WinQuake/d_iface.h
index 8f826b6..071ea45 100644
--- a/quake/src/WinQuake/d_iface.h
+++ b/quake/src/WinQuake/d_iface.h
@@ -32,7 +32,8 @@
 } emitpoint_t;

 

 typedef enum {

-	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2

+	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2,

+	ptype_t_max = 1 << 30

 } ptype_t;

 

 // !!! if this is changed, it must be changed in d_ifacea.h too !!!

diff --git a/quake/src/WinQuake/d_init.c b/quake/src/WinQuake/d_init.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_init.c
rename to quake/src/WinQuake/d_init.cpp
diff --git a/quake/src/WinQuake/d_modech.c b/quake/src/WinQuake/d_modech.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_modech.c
rename to quake/src/WinQuake/d_modech.cpp
diff --git a/quake/src/WinQuake/d_part.c b/quake/src/WinQuake/d_part.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_part.c
rename to quake/src/WinQuake/d_part.cpp
diff --git a/quake/src/WinQuake/d_polyse.c b/quake/src/WinQuake/d_polyse.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_polyse.c
rename to quake/src/WinQuake/d_polyse.cpp
diff --git a/quake/src/WinQuake/d_scan.c b/quake/src/WinQuake/d_scan.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_scan.c
rename to quake/src/WinQuake/d_scan.cpp
diff --git a/quake/src/WinQuake/d_sky.c b/quake/src/WinQuake/d_sky.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_sky.c
rename to quake/src/WinQuake/d_sky.cpp
diff --git a/quake/src/WinQuake/d_sprite.c b/quake/src/WinQuake/d_sprite.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_sprite.c
rename to quake/src/WinQuake/d_sprite.cpp
diff --git a/quake/src/WinQuake/d_surf.c b/quake/src/WinQuake/d_surf.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_surf.c
rename to quake/src/WinQuake/d_surf.cpp
diff --git a/quake/src/WinQuake/d_vars.c b/quake/src/WinQuake/d_vars.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_vars.c
rename to quake/src/WinQuake/d_vars.cpp
diff --git a/quake/src/WinQuake/d_zpoint.c b/quake/src/WinQuake/d_zpoint.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/d_zpoint.c
rename to quake/src/WinQuake/d_zpoint.cpp
diff --git a/quake/src/WinQuake/dos_v2.c b/quake/src/WinQuake/dos_v2.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/dos_v2.c
rename to quake/src/WinQuake/dos_v2.cpp
diff --git a/quake/src/WinQuake/draw.c b/quake/src/WinQuake/draw.cpp
old mode 100644
new mode 100755
similarity index 98%
rename from quake/src/WinQuake/draw.c
rename to quake/src/WinQuake/draw.cpp
index 39114f5..ce0dd34
--- a/quake/src/WinQuake/draw.c
+++ b/quake/src/WinQuake/draw.cpp
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 // draw.c -- this is the only file outside the refresh that touches the
 // vid buffer
@@ -51,7 +51,7 @@
 int			menu_numcachepics;
 
 
-qpic_t	*Draw_PicFromWad (char *name)
+qpic_t	*Draw_PicFromWad (const char *name)
 {
 	return W_GetLumpName (name);
 }
@@ -61,7 +61,7 @@
 Draw_CachePic
 ================
 */
-qpic_t	*Draw_CachePic (char *path)
+qpic_t	*Draw_CachePic (const char *path)
 {
 	cachepic_t	*pic;
 	int			i;
@@ -228,7 +228,7 @@
 Draw_String
 ================
 */
-void Draw_String (int x, int y, char *str)
+void Draw_String (int x, int y, const char *str)
 {
 	while (*str)
 	{
diff --git a/quake/src/WinQuake/draw.h b/quake/src/WinQuake/draw.h
index e54999c..465d95b 100644
--- a/quake/src/WinQuake/draw.h
+++ b/quake/src/WinQuake/draw.h
@@ -1,40 +1,40 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-// draw.h -- these are the only functions outside the refresh allowed

-// to touch the vid buffer

-

-extern	qpic_t		*draw_disc;	// also used on sbar

-

-void Draw_Init (void);

-void Draw_Character (int x, int y, int num);

-void Draw_DebugChar (char num);

-void Draw_Pic (int x, int y, qpic_t *pic);

-void Draw_TransPic (int x, int y, qpic_t *pic);

-void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation);

-void Draw_ConsoleBackground (int lines);

-void Draw_BeginDisc (void);

-void Draw_EndDisc (void);

-void Draw_TileClear (int x, int y, int w, int h);

-void Draw_Fill (int x, int y, int w, int h, int c);

-void Draw_FadeScreen (void);

-void Draw_String (int x, int y, char *str);

-qpic_t *Draw_PicFromWad (char *name);

-qpic_t *Draw_CachePic (char *path);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+// draw.h -- these are the only functions outside the refresh allowed
+// to touch the vid buffer
+
+extern	qpic_t		*draw_disc;	// also used on sbar
+
+void Draw_Init (void);
+void Draw_Character (int x, int y, int num);
+void Draw_DebugChar (char num);
+void Draw_Pic (int x, int y, qpic_t *pic);
+void Draw_TransPic (int x, int y, qpic_t *pic);
+void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation);
+void Draw_ConsoleBackground (int lines);
+void Draw_BeginDisc (void);
+void Draw_EndDisc (void);
+void Draw_TileClear (int x, int y, int w, int h);
+void Draw_Fill (int x, int y, int w, int h, int c);
+void Draw_FadeScreen (void);
+void Draw_String (int x, int y, const char *str);
+qpic_t *Draw_PicFromWad (const char *name);
+qpic_t *Draw_CachePic (const char *path);
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/D3D.H b/quake/src/WinQuake/dxsdk/SDK/INC/D3D.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/D3DCAPS.H b/quake/src/WinQuake/dxsdk/SDK/INC/D3DCAPS.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/D3DRM.H b/quake/src/WinQuake/dxsdk/SDK/INC/D3DRM.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/D3DRMDEF.H b/quake/src/WinQuake/dxsdk/SDK/INC/D3DRMDEF.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/D3DRMOBJ.H b/quake/src/WinQuake/dxsdk/SDK/INC/D3DRMOBJ.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/D3DRMWIN.H b/quake/src/WinQuake/dxsdk/SDK/INC/D3DRMWIN.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/D3DTYPES.H b/quake/src/WinQuake/dxsdk/SDK/INC/D3DTYPES.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/DDRAW.H b/quake/src/WinQuake/dxsdk/SDK/INC/DDRAW.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/DINPUT.H b/quake/src/WinQuake/dxsdk/SDK/INC/DINPUT.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/DPLAY.H b/quake/src/WinQuake/dxsdk/SDK/INC/DPLAY.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/DSETUP.H b/quake/src/WinQuake/dxsdk/SDK/INC/DSETUP.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/DSOUND.H b/quake/src/WinQuake/dxsdk/SDK/INC/DSOUND.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/INC/FASTFILE.H b/quake/src/WinQuake/dxsdk/SDK/INC/FASTFILE.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/dxsdk/SDK/LIB/DINPUT.LIB b/quake/src/WinQuake/dxsdk/SDK/LIB/DINPUT.LIB
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/WinQuake/dxsdk/SDK/LIB/DXGUID.LIB b/quake/src/WinQuake/dxsdk/SDK/LIB/DXGUID.LIB
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/WinQuake/gl_draw.c b/quake/src/WinQuake/gl_draw.c
deleted file mode 100644
index 61480b4..0000000
--- a/quake/src/WinQuake/gl_draw.c
+++ /dev/null
@@ -1,1297 +0,0 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-
-// draw.c -- this is the only file outside the refresh that touches the
-// vid buffer
-
-#include "quakedef.h"
-
-#define GL_COLOR_INDEX8_EXT     0x80E5
-
-extern unsigned char d_15to8table[65536];
-
-cvar_t		gl_nobind = {"gl_nobind", "0"};
-cvar_t		gl_max_size = {"gl_max_size", "1024"};
-cvar_t		gl_picmip = {"gl_picmip", "0"};
-
-byte		*draw_chars;				// 8*8 graphic characters
-qpic_t		*draw_disc;
-qpic_t		*draw_backtile;
-
-int			translate_texture;
-int			char_texture;
-
-typedef struct
-{
-	int		texnum;
-	float	sl, tl, sh, th;
-} glpic_t;
-
-byte		conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)];
-qpic_t		*conback = (qpic_t *)&conback_buffer;
-
-int		gl_lightmap_format = 4;
-int		gl_solid_format = 3;
-int		gl_alpha_format = 4;
-
-int		gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
-int		gl_filter_max = GL_LINEAR;
-
-
-int		texels;
-
-typedef struct
-{
-	int		texnum;
-	char	identifier[64];
-	int		width, height;
-	qboolean	mipmap;
-} gltexture_t;
-
-#define	MAX_GLTEXTURES	1024
-gltexture_t	gltextures[MAX_GLTEXTURES];
-int			numgltextures;
-
-
-void GL_Bind (int texnum)
-{
-	if (gl_nobind.value)
-		texnum = char_texture;
-	if (currenttexture == texnum)
-		return;
-	currenttexture = texnum;
-#ifdef _WIN32
-	bindTexFunc (GL_TEXTURE_2D, texnum);
-#else
-	glBindTexture(GL_TEXTURE_2D, texnum);
-#endif
-}
-
-
-/*
-=============================================================================
-
-  scrap allocation
-
-  Allocate all the little status bar obejcts into a single texture
-  to crutch up stupid hardware / drivers
-
-=============================================================================
-*/
-
-#define	MAX_SCRAPS		2
-#define	BLOCK_WIDTH		256
-#define	BLOCK_HEIGHT	256
-
-int			scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
-byte		scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
-qboolean	scrap_dirty;
-int			scrap_texnum;
-
-// returns a texture number and the position inside it
-int Scrap_AllocBlock (int w, int h, int *x, int *y)
-{
-	int		i, j;
-	int		best, best2;
-	int		bestx;
-	int		texnum;
-
-	for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
-	{
-		best = BLOCK_HEIGHT;
-
-		for (i=0 ; i<BLOCK_WIDTH-w ; i++)
-		{
-			best2 = 0;
-
-			for (j=0 ; j<w ; j++)
-			{
-				if (scrap_allocated[texnum][i+j] >= best)
-					break;
-				if (scrap_allocated[texnum][i+j] > best2)
-					best2 = scrap_allocated[texnum][i+j];
-			}
-			if (j == w)
-			{	// this is a valid spot
-				*x = i;
-				*y = best = best2;
-			}
-		}
-
-		if (best + h > BLOCK_HEIGHT)
-			continue;
-
-		for (i=0 ; i<w ; i++)
-			scrap_allocated[texnum][*x + i] = best + h;
-
-		return texnum;
-	}
-
-	Sys_Error ("Scrap_AllocBlock: full");
-}
-
-int	scrap_uploads;
-
-void Scrap_Upload (void)
-{
-	int		texnum;
-
-	scrap_uploads++;
-
-	for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) {
-		GL_Bind(scrap_texnum + texnum);
-		GL_Upload8 (scrap_texels[texnum], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);
-	}
-	scrap_dirty = false;
-}
-
-//=============================================================================
-/* Support Routines */
-
-typedef struct cachepic_s
-{
-	char		name[MAX_QPATH];
-	qpic_t		pic;
-	byte		padding[32];	// for appended glpic
-} cachepic_t;
-
-#define	MAX_CACHED_PICS		128
-cachepic_t	menu_cachepics[MAX_CACHED_PICS];
-int			menu_numcachepics;
-
-byte		menuplyr_pixels[4096];
-
-int		pic_texels;
-int		pic_count;
-
-qpic_t *Draw_PicFromWad (char *name)
-{
-	qpic_t	*p;
-	glpic_t	*gl;
-
-	p = W_GetLumpName (name);
-	gl = (glpic_t *)p->data;
-
-	// load little ones into the scrap
-	if (p->width < 64 && p->height < 64)
-	{
-		int		x, y;
-		int		i, j, k;
-		int		texnum;
-
-		texnum = Scrap_AllocBlock (p->width, p->height, &x, &y);
-		scrap_dirty = true;
-		k = 0;
-		for (i=0 ; i<p->height ; i++)
-			for (j=0 ; j<p->width ; j++, k++)
-				scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];
-		texnum += scrap_texnum;
-		gl->texnum = texnum;
-		gl->sl = (x+0.01)/(float)BLOCK_WIDTH;
-		gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;
-		gl->tl = (y+0.01)/(float)BLOCK_WIDTH;
-		gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;
-
-		pic_count++;
-		pic_texels += p->width*p->height;
-	}
-	else
-	{
-		gl->texnum = GL_LoadPicTexture (p);
-		gl->sl = 0;
-		gl->sh = 1;
-		gl->tl = 0;
-		gl->th = 1;
-	}
-	return p;
-}
-
-
-/*
-================
-Draw_CachePic
-================
-*/
-qpic_t	*Draw_CachePic (char *path)
-{
-	cachepic_t	*pic;
-	int			i;
-	qpic_t		*dat;
-	glpic_t		*gl;
-
-	for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
-		if (!strcmp (path, pic->name))
-			return &pic->pic;
-
-	if (menu_numcachepics == MAX_CACHED_PICS)
-		Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
-	menu_numcachepics++;
-	strcpy (pic->name, path);
-
-//
-// load the pic from disk
-//
-	dat = (qpic_t *)COM_LoadTempFile (path);	
-	if (!dat)
-		Sys_Error ("Draw_CachePic: failed to load %s", path);
-	SwapPic (dat);
-
-	// HACK HACK HACK --- we need to keep the bytes for
-	// the translatable player picture just for the menu
-	// configuration dialog
-	if (!strcmp (path, "gfx/menuplyr.lmp"))
-		memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
-
-	pic->pic.width = dat->width;
-	pic->pic.height = dat->height;
-
-	gl = (glpic_t *)pic->pic.data;
-	gl->texnum = GL_LoadPicTexture (dat);
-	gl->sl = 0;
-	gl->sh = 1;
-	gl->tl = 0;
-	gl->th = 1;
-
-	return &pic->pic;
-}
-
-
-void Draw_CharToConback (int num, byte *dest)
-{
-	int		row, col;
-	byte	*source;
-	int		drawline;
-	int		x;
-
-	row = num>>4;
-	col = num&15;
-	source = draw_chars + (row<<10) + (col<<3);
-
-	drawline = 8;
-
-	while (drawline--)
-	{
-		for (x=0 ; x<8 ; x++)
-			if (source[x] != 255)
-				dest[x] = 0x60 + source[x];
-		source += 128;
-		dest += 320;
-	}
-
-}
-
-typedef struct
-{
-	char *name;
-	int	minimize, maximize;
-} glmode_t;
-
-glmode_t modes[] = {
-	{"GL_NEAREST", GL_NEAREST, GL_NEAREST},
-	{"GL_LINEAR", GL_LINEAR, GL_LINEAR},
-	{"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
-	{"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
-	{"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
-	{"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
-};
-
-/*
-===============
-Draw_TextureMode_f
-===============
-*/
-void Draw_TextureMode_f (void)
-{
-	int		i;
-	gltexture_t	*glt;
-
-	if (Cmd_Argc() == 1)
-	{
-		for (i=0 ; i< 6 ; i++)
-			if (gl_filter_min == modes[i].minimize)
-			{
-				Con_Printf ("%s\n", modes[i].name);
-				return;
-			}
-		Con_Printf ("current filter is unknown???\n");
-		return;
-	}
-
-	for (i=0 ; i< 6 ; i++)
-	{
-		if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
-			break;
-	}
-	if (i == 6)
-	{
-		Con_Printf ("bad filter name\n");
-		return;
-	}
-
-	gl_filter_min = modes[i].minimize;
-	gl_filter_max = modes[i].maximize;
-
-	// change all the existing mipmap texture objects
-	for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
-	{
-		if (glt->mipmap)
-		{
-			GL_Bind (glt->texnum);
-			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
-		}
-	}
-}
-
-/*
-===============
-Draw_Init
-===============
-*/
-void Draw_Init (void)
-{
-	int		i;
-	qpic_t	*cb;
-	byte	*dest, *src;
-	int		x, y;
-	char	ver[40];
-	glpic_t	*gl;
-	int		start;
-	byte	*ncdata;
-	int		f, fstep;
-
-
-	Cvar_RegisterVariable (&gl_nobind);
-	Cvar_RegisterVariable (&gl_max_size);
-	Cvar_RegisterVariable (&gl_picmip);
-
-	// 3dfx can only handle 256 wide textures
-	if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) ||
-		strstr((char *)gl_renderer, "Glide"))
-		Cvar_Set ("gl_max_size", "256");
-
-	Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
-
-	// load the console background and the charset
-	// by hand, because we need to write the version
-	// string into the background before turning
-	// it into a texture
-	draw_chars = W_GetLumpName ("conchars");
-	for (i=0 ; i<256*64 ; i++)
-		if (draw_chars[i] == 0)
-			draw_chars[i] = 255;	// proper transparent color
-
-	// now turn them into textures
-	char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
-
-	start = Hunk_LowMark();
-
-	cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp");	
-	if (!cb)
-		Sys_Error ("Couldn't load gfx/conback.lmp");
-	SwapPic (cb);
-
-	// hack the version number directly into the pic
-#if defined(__linux__)
-	sprintf (ver, "(Linux %2.2f, gl %4.2f) %4.2f", (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
-#else
-	sprintf (ver, "(gl %4.2f) %4.2f", (float)GLQUAKE_VERSION, (float)VERSION);
-#endif
-	dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver);
-	y = strlen(ver);
-	for (x=0 ; x<y ; x++)
-		Draw_CharToConback (ver[x], dest+(x<<3));
-
-#if 0
-	conback->width = vid.conwidth;
-	conback->height = vid.conheight;
-
- 	// scale console to vid size
- 	dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback");
- 
- 	for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth)
- 	{
- 		src = cb->data + cb->width * (y*cb->height/vid.conheight);
- 		if (vid.conwidth == cb->width)
- 			memcpy (dest, src, vid.conwidth);
- 		else
- 		{
- 			f = 0;
- 			fstep = cb->width*0x10000/vid.conwidth;
- 			for (x=0 ; x<vid.conwidth ; x+=4)
- 			{
- 				dest[x] = src[f>>16];
- 				f += fstep;
- 				dest[x+1] = src[f>>16];
- 				f += fstep;
- 				dest[x+2] = src[f>>16];
- 				f += fstep;
- 				dest[x+3] = src[f>>16];
- 				f += fstep;
- 			}
- 		}
- 	}
-#else
-	conback->width = cb->width;
-	conback->height = cb->height;
-	ncdata = cb->data;
-#endif
-
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-	gl = (glpic_t *)conback->data;
-	gl->texnum = GL_LoadTexture ("conback", conback->width, conback->height, ncdata, false, false);
-	gl->sl = 0;
-	gl->sh = 1;
-	gl->tl = 0;
-	gl->th = 1;
-	conback->width = vid.width;
-	conback->height = vid.height;
-
-	// free loaded console
-	Hunk_FreeToLowMark(start);
-
-	// save a texture slot for translated picture
-	translate_texture = texture_extension_number++;
-
-	// save slots for scraps
-	scrap_texnum = texture_extension_number;
-	texture_extension_number += MAX_SCRAPS;
-
-	//
-	// get the other pics we need
-	//
-	draw_disc = Draw_PicFromWad ("disc");
-	draw_backtile = Draw_PicFromWad ("backtile");
-}
-
-
-
-/*
-================
-Draw_Character
-
-Draws one 8*8 graphics character with 0 being transparent.
-It can be clipped to the top of the screen to allow the console to be
-smoothly scrolled off.
-================
-*/
-void Draw_Character (int x, int y, int num)
-{
-	byte			*dest;
-	byte			*source;
-	unsigned short	*pusdest;
-	int				drawline;	
-	int				row, col;
-	float			frow, fcol, size;
-
-	if (num == 32)
-		return;		// space
-
-	num &= 255;
-	
-	if (y <= -8)
-		return;			// totally off screen
-
-	row = num>>4;
-	col = num&15;
-
-	frow = row*0.0625;
-	fcol = col*0.0625;
-	size = 0.0625;
-
-	GL_Bind (char_texture);
-
-	glBegin (GL_QUADS);
-	glTexCoord2f (fcol, frow);
-	glVertex2f (x, y);
-	glTexCoord2f (fcol + size, frow);
-	glVertex2f (x+8, y);
-	glTexCoord2f (fcol + size, frow + size);
-	glVertex2f (x+8, y+8);
-	glTexCoord2f (fcol, frow + size);
-	glVertex2f (x, y+8);
-	glEnd ();
-}
-
-/*
-================
-Draw_String
-================
-*/
-void Draw_String (int x, int y, char *str)
-{
-	while (*str)
-	{
-		Draw_Character (x, y, *str);
-		str++;
-		x += 8;
-	}
-}
-
-/*
-================
-Draw_DebugChar
-
-Draws a single character directly to the upper right corner of the screen.
-This is for debugging lockups by drawing different chars in different parts
-of the code.
-================
-*/
-void Draw_DebugChar (char num)
-{
-}
-
-/*
-=============
-Draw_AlphaPic
-=============
-*/
-void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha)
-{
-	byte			*dest, *source;
-	unsigned short	*pusdest;
-	int				v, u;
-	glpic_t			*gl;
-
-	if (scrap_dirty)
-		Scrap_Upload ();
-	gl = (glpic_t *)pic->data;
-	glDisable(GL_ALPHA_TEST);
-	glEnable (GL_BLEND);
-//	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-//	glCullFace(GL_FRONT);
-	glColor4f (1,1,1,alpha);
-	GL_Bind (gl->texnum);
-	glBegin (GL_QUADS);
-	glTexCoord2f (gl->sl, gl->tl);
-	glVertex2f (x, y);
-	glTexCoord2f (gl->sh, gl->tl);
-	glVertex2f (x+pic->width, y);
-	glTexCoord2f (gl->sh, gl->th);
-	glVertex2f (x+pic->width, y+pic->height);
-	glTexCoord2f (gl->sl, gl->th);
-	glVertex2f (x, y+pic->height);
-	glEnd ();
-	glColor4f (1,1,1,1);
-	glEnable(GL_ALPHA_TEST);
-	glDisable (GL_BLEND);
-}
-
-
-/*
-=============
-Draw_Pic
-=============
-*/
-void Draw_Pic (int x, int y, qpic_t *pic)
-{
-	byte			*dest, *source;
-	unsigned short	*pusdest;
-	int				v, u;
-	glpic_t			*gl;
-
-	if (scrap_dirty)
-		Scrap_Upload ();
-	gl = (glpic_t *)pic->data;
-	glColor4f (1,1,1,1);
-	GL_Bind (gl->texnum);
-	glBegin (GL_QUADS);
-	glTexCoord2f (gl->sl, gl->tl);
-	glVertex2f (x, y);
-	glTexCoord2f (gl->sh, gl->tl);
-	glVertex2f (x+pic->width, y);
-	glTexCoord2f (gl->sh, gl->th);
-	glVertex2f (x+pic->width, y+pic->height);
-	glTexCoord2f (gl->sl, gl->th);
-	glVertex2f (x, y+pic->height);
-	glEnd ();
-}
-
-
-/*
-=============
-Draw_TransPic
-=============
-*/
-void Draw_TransPic (int x, int y, qpic_t *pic)
-{
-	byte	*dest, *source, tbyte;
-	unsigned short	*pusdest;
-	int				v, u;
-
-	if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
-		 (unsigned)(y + pic->height) > vid.height)
-	{
-		Sys_Error ("Draw_TransPic: bad coordinates");
-	}
-		
-	Draw_Pic (x, y, pic);
-}
-
-
-/*
-=============
-Draw_TransPicTranslate
-
-Only used for the player color selection menu
-=============
-*/
-void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
-{
-	int				v, u, c;
-	unsigned		trans[64*64], *dest;
-	byte			*src;
-	int				p;
-
-	GL_Bind (translate_texture);
-
-	c = pic->width * pic->height;
-
-	dest = trans;
-	for (v=0 ; v<64 ; v++, dest += 64)
-	{
-		src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];
-		for (u=0 ; u<64 ; u++)
-		{
-			p = src[(u*pic->width)>>6];
-			if (p == 255)
-				dest[u] = p;
-			else
-				dest[u] =  d_8to24table[translation[p]];
-		}
-	}
-
-	glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
-
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-	glColor3f (1,1,1);
-	glBegin (GL_QUADS);
-	glTexCoord2f (0, 0);
-	glVertex2f (x, y);
-	glTexCoord2f (1, 0);
-	glVertex2f (x+pic->width, y);
-	glTexCoord2f (1, 1);
-	glVertex2f (x+pic->width, y+pic->height);
-	glTexCoord2f (0, 1);
-	glVertex2f (x, y+pic->height);
-	glEnd ();
-}
-
-
-/*
-================
-Draw_ConsoleBackground
-
-================
-*/
-void Draw_ConsoleBackground (int lines)
-{
-	int y = (vid.height * 3) >> 2;
-
-	if (lines > y)
-		Draw_Pic(0, lines - vid.height, conback);
-	else
-		Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
-}
-
-
-/*
-=============
-Draw_TileClear
-
-This repeats a 64*64 tile graphic to fill the screen around a sized down
-refresh window.
-=============
-*/
-void Draw_TileClear (int x, int y, int w, int h)
-{
-	glColor3f (1,1,1);
-	GL_Bind (*(int *)draw_backtile->data);
-	glBegin (GL_QUADS);
-	glTexCoord2f (x/64.0, y/64.0);
-	glVertex2f (x, y);
-	glTexCoord2f ( (x+w)/64.0, y/64.0);
-	glVertex2f (x+w, y);
-	glTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
-	glVertex2f (x+w, y+h);
-	glTexCoord2f ( x/64.0, (y+h)/64.0 );
-	glVertex2f (x, y+h);
-	glEnd ();
-}
-
-
-/*
-=============
-Draw_Fill
-
-Fills a box of pixels with a single color
-=============
-*/
-void Draw_Fill (int x, int y, int w, int h, int c)
-{
-	glDisable (GL_TEXTURE_2D);
-	glColor3f (host_basepal[c*3]/255.0,
-		host_basepal[c*3+1]/255.0,
-		host_basepal[c*3+2]/255.0);
-
-	glBegin (GL_QUADS);
-
-	glVertex2f (x,y);
-	glVertex2f (x+w, y);
-	glVertex2f (x+w, y+h);
-	glVertex2f (x, y+h);
-
-	glEnd ();
-	glColor3f (1,1,1);
-	glEnable (GL_TEXTURE_2D);
-}
-//=============================================================================
-
-/*
-================
-Draw_FadeScreen
-
-================
-*/
-void Draw_FadeScreen (void)
-{
-	glEnable (GL_BLEND);
-	glDisable (GL_TEXTURE_2D);
-	glColor4f (0, 0, 0, 0.8);
-	glBegin (GL_QUADS);
-
-	glVertex2f (0,0);
-	glVertex2f (vid.width, 0);
-	glVertex2f (vid.width, vid.height);
-	glVertex2f (0, vid.height);
-
-	glEnd ();
-	glColor4f (1,1,1,1);
-	glEnable (GL_TEXTURE_2D);
-	glDisable (GL_BLEND);
-
-	Sbar_Changed();
-}
-
-//=============================================================================
-
-/*
-================
-Draw_BeginDisc
-
-Draws the little blue disc in the corner of the screen.
-Call before beginning any disc IO.
-================
-*/
-void Draw_BeginDisc (void)
-{
-	if (!draw_disc)
-		return;
-	glDrawBuffer  (GL_FRONT);
-	Draw_Pic (vid.width - 24, 0, draw_disc);
-	glDrawBuffer  (GL_BACK);
-}
-
-
-/*
-================
-Draw_EndDisc
-
-Erases the disc icon.
-Call after completing any disc IO
-================
-*/
-void Draw_EndDisc (void)
-{
-}
-
-/*
-================
-GL_Set2D
-
-Setup as if the screen was 320*200
-================
-*/
-void GL_Set2D (void)
-{
-	glViewport (glx, gly, glwidth, glheight);
-
-	glMatrixMode(GL_PROJECTION);
-    glLoadIdentity ();
-	glOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
-
-	glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity ();
-
-	glDisable (GL_DEPTH_TEST);
-	glDisable (GL_CULL_FACE);
-	glDisable (GL_BLEND);
-	glEnable (GL_ALPHA_TEST);
-//	glDisable (GL_ALPHA_TEST);
-
-	glColor4f (1,1,1,1);
-}
-
-//====================================================================
-
-/*
-================
-GL_FindTexture
-================
-*/
-int GL_FindTexture (char *identifier)
-{
-	int		i;
-	gltexture_t	*glt;
-
-	for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
-	{
-		if (!strcmp (identifier, glt->identifier))
-			return gltextures[i].texnum;
-	}
-
-	return -1;
-}
-
-/*
-================
-GL_ResampleTexture
-================
-*/
-void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight)
-{
-	int		i, j;
-	unsigned	*inrow;
-	unsigned	frac, fracstep;
-
-	fracstep = inwidth*0x10000/outwidth;
-	for (i=0 ; i<outheight ; i++, out += outwidth)
-	{
-		inrow = in + inwidth*(i*inheight/outheight);
-		frac = fracstep >> 1;
-		for (j=0 ; j<outwidth ; j+=4)
-		{
-			out[j] = inrow[frac>>16];
-			frac += fracstep;
-			out[j+1] = inrow[frac>>16];
-			frac += fracstep;
-			out[j+2] = inrow[frac>>16];
-			frac += fracstep;
-			out[j+3] = inrow[frac>>16];
-			frac += fracstep;
-		}
-	}
-}
-
-/*
-================
-GL_Resample8BitTexture -- JACK
-================
-*/
-void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out,  int outwidth, int outheight)
-{
-	int		i, j;
-	unsigned	char *inrow;
-	unsigned	frac, fracstep;
-
-	fracstep = inwidth*0x10000/outwidth;
-	for (i=0 ; i<outheight ; i++, out += outwidth)
-	{
-		inrow = in + inwidth*(i*inheight/outheight);
-		frac = fracstep >> 1;
-		for (j=0 ; j<outwidth ; j+=4)
-		{
-			out[j] = inrow[frac>>16];
-			frac += fracstep;
-			out[j+1] = inrow[frac>>16];
-			frac += fracstep;
-			out[j+2] = inrow[frac>>16];
-			frac += fracstep;
-			out[j+3] = inrow[frac>>16];
-			frac += fracstep;
-		}
-	}
-}
-
-
-/*
-================
-GL_MipMap
-
-Operates in place, quartering the size of the texture
-================
-*/
-void GL_MipMap (byte *in, int width, int height)
-{
-	int		i, j;
-	byte	*out;
-
-	width <<=2;
-	height >>= 1;
-	out = in;
-	for (i=0 ; i<height ; i++, in+=width)
-	{
-		for (j=0 ; j<width ; j+=8, out+=4, in+=8)
-		{
-			out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
-			out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
-			out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
-			out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
-		}
-	}
-}
-
-/*
-================
-GL_MipMap8Bit
-
-Mipping for 8 bit textures
-================
-*/
-void GL_MipMap8Bit (byte *in, int width, int height)
-{
-	int		i, j;
-	unsigned short     r,g,b;
-	byte	*out, *at1, *at2, *at3, *at4;
-
-//	width <<=2;
-	height >>= 1;
-	out = in;
-	for (i=0 ; i<height ; i++, in+=width)
-	{
-		for (j=0 ; j<width ; j+=2, out+=1, in+=2)
-		{
-			at1 = (byte *) (d_8to24table + in[0]);
-			at2 = (byte *) (d_8to24table + in[1]);
-			at3 = (byte *) (d_8to24table + in[width+0]);
-			at4 = (byte *) (d_8to24table + in[width+1]);
-
- 			r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
- 			g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
- 			b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
-
-			out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
-		}
-	}
-}
-
-/*
-===============
-GL_Upload32
-===============
-*/
-void GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap, qboolean alpha)
-{
-	int			samples;
-static	unsigned	scaled[1024*512];	// [512*256];
-	int			scaled_width, scaled_height;
-
-	for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
-		;
-	for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
-		;
-
-	scaled_width >>= (int)gl_picmip.value;
-	scaled_height >>= (int)gl_picmip.value;
-
-	if (scaled_width > gl_max_size.value)
-		scaled_width = gl_max_size.value;
-	if (scaled_height > gl_max_size.value)
-		scaled_height = gl_max_size.value;
-
-	if (scaled_width * scaled_height > sizeof(scaled)/4)
-		Sys_Error ("GL_LoadTexture: too big");
-
-	samples = alpha ? gl_alpha_format : gl_solid_format;
-
-#if 0
-	if (mipmap)
-		gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, trans);
-	else if (scaled_width == width && scaled_height == height)
-		glTexImage2D (GL_TEXTURE_2D, 0, samples, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
-	else
-	{
-		gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, trans,
-			scaled_width, scaled_height, GL_UNSIGNED_BYTE, scaled);
-		glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
-	}
-#else
-texels += scaled_width * scaled_height;
-
-	if (scaled_width == width && scaled_height == height)
-	{
-		if (!mipmap)
-		{
-			glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-			goto done;
-		}
-		memcpy (scaled, data, width*height*4);
-	}
-	else
-		GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
-
-	glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
-	if (mipmap)
-	{
-		int		miplevel;
-
-		miplevel = 0;
-		while (scaled_width > 1 || scaled_height > 1)
-		{
-			GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
-			scaled_width >>= 1;
-			scaled_height >>= 1;
-			if (scaled_width < 1)
-				scaled_width = 1;
-			if (scaled_height < 1)
-				scaled_height = 1;
-			miplevel++;
-			glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
-		}
-	}
-done: ;
-#endif
-
-
-	if (mipmap)
-	{
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
-	}
-	else
-	{
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
-	}
-}
-
-void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha) 
-{
-	int			i, s;
-	qboolean	noalpha;
-	int			p;
-	static unsigned j;
-	int			samples;
-    static	unsigned char scaled[1024*512];	// [512*256];
-	int			scaled_width, scaled_height;
-
-	s = width*height;
-	// if there are no transparent pixels, make it a 3 component
-	// texture even if it was specified as otherwise
-	if (alpha)
-	{
-		noalpha = true;
-		for (i=0 ; i<s ; i++)
-		{
-			if (data[i] == 255)
-				noalpha = false;
-		}
-
-		if (alpha && noalpha)
-			alpha = false;
-	}
-	for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
-		;
-	for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
-		;
-
-	scaled_width >>= (int)gl_picmip.value;
-	scaled_height >>= (int)gl_picmip.value;
-
-	if (scaled_width > gl_max_size.value)
-		scaled_width = gl_max_size.value;
-	if (scaled_height > gl_max_size.value)
-		scaled_height = gl_max_size.value;
-
-	if (scaled_width * scaled_height > sizeof(scaled))
-		Sys_Error ("GL_LoadTexture: too big");
-
-	samples = 1; // alpha ? gl_alpha_format : gl_solid_format;
-
-	texels += scaled_width * scaled_height;
-
-	if (scaled_width == width && scaled_height == height)
-	{
-		if (!mipmap)
-		{
-			glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
-			goto done;
-		}
-		memcpy (scaled, data, width*height);
-	}
-	else
-		GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
-
-	glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
-	if (mipmap)
-	{
-		int		miplevel;
-
-		miplevel = 0;
-		while (scaled_width > 1 || scaled_height > 1)
-		{
-			GL_MipMap8Bit ((byte *)scaled, scaled_width, scaled_height);
-			scaled_width >>= 1;
-			scaled_height >>= 1;
-			if (scaled_width < 1)
-				scaled_width = 1;
-			if (scaled_height < 1)
-				scaled_height = 1;
-			miplevel++;
-			glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
-		}
-	}
-done: ;
-
-
-	if (mipmap)
-	{
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
-	}
-	else
-	{
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
-	}
-}
-
-/*
-===============
-GL_Upload8
-===============
-*/
-void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
-{
-static	unsigned	trans[640*480];		// FIXME, temporary
-	int			i, s;
-	qboolean	noalpha;
-	int			p;
-
-	s = width*height;
-	// if there are no transparent pixels, make it a 3 component
-	// texture even if it was specified as otherwise
-	if (alpha)
-	{
-		noalpha = true;
-		for (i=0 ; i<s ; i++)
-		{
-			p = data[i];
-			if (p == 255)
-				noalpha = false;
-			trans[i] = d_8to24table[p];
-		}
-
-		if (alpha && noalpha)
-			alpha = false;
-	}
-	else
-	{
-		if (s&3)
-			Sys_Error ("GL_Upload8: s&3");
-		for (i=0 ; i<s ; i+=4)
-		{
-			trans[i] = d_8to24table[data[i]];
-			trans[i+1] = d_8to24table[data[i+1]];
-			trans[i+2] = d_8to24table[data[i+2]];
-			trans[i+3] = d_8to24table[data[i+3]];
-		}
-	}
-
- 	if (VID_Is8bit() && !alpha && (data!=scrap_texels[0])) {
- 		GL_Upload8_EXT (data, width, height, mipmap, alpha);
- 		return;
-	}
-	GL_Upload32 (trans, width, height, mipmap, alpha);
-}
-
-/*
-================
-GL_LoadTexture
-================
-*/
-int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha)
-{
-	qboolean	noalpha;
-	int			i, p, s;
-	gltexture_t	*glt;
-
-	// see if the texture is allready present
-	if (identifier[0])
-	{
-		for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
-		{
-			if (!strcmp (identifier, glt->identifier))
-			{
-				if (width != glt->width || height != glt->height)
-					Sys_Error ("GL_LoadTexture: cache mismatch");
-				return gltextures[i].texnum;
-			}
-		}
-	}
-	else {
-		glt = &gltextures[numgltextures];
-		numgltextures++;

-	}
-
-	strcpy (glt->identifier, identifier);
-	glt->texnum = texture_extension_number;
-	glt->width = width;
-	glt->height = height;
-	glt->mipmap = mipmap;
-
-	GL_Bind(texture_extension_number );
-
-	GL_Upload8 (data, width, height, mipmap, alpha);
-
-	texture_extension_number++;
-
-	return texture_extension_number-1;
-}
-
-/*
-================
-GL_LoadPicTexture
-================
-*/
-int GL_LoadPicTexture (qpic_t *pic)
-{
-	return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true);
-}
-
-/****************************************/
-
-static GLenum oldtarget = TEXTURE0_SGIS;
-
-void GL_SelectTexture (GLenum target) 
-{
-	if (!gl_mtexable)
-		return;
-	qglSelectTextureSGIS(target);
-	if (target == oldtarget) 
-		return;
-	cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture;
-	currenttexture = cnttextures[target-TEXTURE0_SGIS];
-	oldtarget = target;
-}
diff --git a/quake/src/WinQuake/gl_draw.cpp b/quake/src/WinQuake/gl_draw.cpp
new file mode 100755
index 0000000..986df88
--- /dev/null
+++ b/quake/src/WinQuake/gl_draw.cpp
@@ -0,0 +1,2096 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+// draw.c -- this is the only file outside the refresh that touches the
+// vid buffer
+
+#include "quakedef.h"
+
+#define GL_COLOR_INDEX8_EXT     0x80E5
+
+
+cvar_t		gl_nobind = CVAR2("gl_nobind", "0");
+cvar_t		gl_max_size = CVAR2("gl_max_size", "1024");
+cvar_t		gl_picmip = CVAR2("gl_picmip", "0");
+
+byte		*draw_chars;				// 8*8 graphic characters
+qpic_t		*draw_disc;
+qpic_t		*draw_backtile;
+
+int			translate_texture;
+int			char_texture;
+
+typedef struct
+{
+  int		texnum;
+  float	sl, tl, sh, th;
+} glpic_t;
+
+typedef union
+{
+    qpic_t qpic;
+    struct {
+        // First part is from qpic
+        int width;
+        int height;
+
+        glpic_t glpic;
+    } g;
+} packedGlpic_t;
+
+typedef union
+{
+    byte buffer[sizeof(qpic_t) + sizeof(glpic_t)];
+    packedGlpic_t pics;
+} conback_t;
+
+conback_t conbackUnion;
+
+#define		conback_buffer (conbackUnion.buffer)
+packedGlpic_t *conback = &conbackUnion.pics;
+
+int		gl_lightmap_format = 4;
+int		gl_solid_format = 3;
+int		gl_alpha_format = 4;
+
+#if 1 // Standard defaults
+int		gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
+int		gl_filter_max = GL_LINEAR;
+#else
+int		gl_filter_min = GL_NEAREST_MIPMAP_NEAREST;
+int		gl_filter_max = GL_NEAREST;
+#endif
+
+int		texels;
+
+typedef struct
+{
+  int		texnum;
+  char	identifier[64];
+  int		width, height;
+  qboolean	mipmap;
+} gltexture_t;
+
+#define	MAX_GLTEXTURES	1024
+gltexture_t	gltextures[MAX_GLTEXTURES];
+int			numgltextures;
+
+// GlQuake creates textures, but never deletes them. This approach works fine on
+// computers with lots of RAM and/or swap, but not so well on our swapless
+// RAM-constrained system.
+//
+// We work around this problem by adding a level of indirection. We
+// hook GL_LoadTexture to store enough information to recreate a texture.
+// Then we hook GL_BindTexture to consult a table to see whether a texture
+// is currently in memory or not. If it isn't, we throw out some other
+// texture and bring the required texture back into memory. In this way
+// we can limit the working set of textures.
+//
+// The texture data is stored in a memory-mapped file that is backed by
+// a file on the sd card. It is recreated each time the game is run. We
+// don't bother deleting it.
+
+#define USE_TEXTURE_STORE
+
+#ifdef USE_TEXTURE_STORE
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+// Allow named textures to be evicted from memory.
+
+#define TEXTURE_STORE_NAME "glquake/texture.store"
+
+class textureStore {
+
+private:
+
+    struct entry
+    {
+        entry* next;
+        entry* prev;
+        int real_texnum;    // < 0 == not assigned
+        byte* pData; // 0 ==> not created by us.
+        size_t size;
+        qboolean alpha;
+        int width;
+        int height;
+        qboolean mipmap;
+
+        entry() {
+            next = 0;
+            prev = 0;
+            real_texnum = -2;
+            pData = 0;
+        }
+
+
+        void unlink() {
+            if (next) {
+                next->prev = prev;
+            }
+            if (prev) {
+                prev->next = next;
+            }
+            next = 0;
+            prev = 0;
+        }
+
+        void insertBefore(entry* e){
+            if (e) {
+                prev = e->prev;
+                if ( prev ) {
+                    prev->next = this;
+                }
+                next = e;
+                e->prev = this;
+            }
+            else {
+                prev = 0;
+                next = 0;
+            }
+        }
+    };
+
+public:
+
+    static textureStore* get() {
+        if (g_pTextureCache == 0) {
+            g_pTextureCache = new textureStore();
+        }
+        return g_pTextureCache;
+    }
+
+    // Equivalent of glBindTexture, but uses the virtual texture table
+
+    void bind(int virtTexNum) {
+        if ( (unsigned int) virtTexNum >= TEXTURE_STORE_NUM_TEXTURES) {
+            Sys_Error("not in the range we're managing");
+        }
+        mBoundTextureID = virtTexNum;
+        entry* e = &mTextures[virtTexNum];
+
+        if ( e->real_texnum == -2) {
+            int realTexNum;
+            glGenTextures( 1, (unsigned int*)&realTexNum);
+            e->real_texnum = realTexNum;
+        }
+
+        if ( e->pData == 0) {
+            glBindTexture(GL_TEXTURE_2D, e->real_texnum);
+            return;
+        }
+
+        update(e);
+    }
+
+    void update(entry* e)
+    {
+        // Update the "LRU" part of the cache
+        unlink(e);
+        e->insertBefore(mFirst);
+        mFirst = e;
+        if (! mLast) {
+            mLast = e;
+        }
+
+        if (e->real_texnum == -1 ) {
+            // Create a real texture
+            // Make sure there is enough room for this texture
+            ensure(e->size);
+
+            int realTexNum;
+            glGenTextures( 1, (unsigned int*)&realTexNum);
+
+            e->real_texnum = realTexNum;
+            glBindTexture(GL_TEXTURE_2D, realTexNum);
+            GL_Upload8 (e->pData, e->width, e->height, e->mipmap,
+                    e->alpha);
+        }
+        else {
+            glBindTexture(GL_TEXTURE_2D, e->real_texnum);
+        }
+    }
+
+    // Create a texture, and remember the data so we can create
+    // it again later.
+
+    void create(int width, int height, byte* data, qboolean mipmap,
+            qboolean alpha) {
+        int size = width * height;
+        if (size + mLength > mCapacity) {
+            Sys_Error("Ran out of virtual texture space. %d", size);
+        };
+        entry* e = &mTextures[mBoundTextureID];
+
+        // Call evict in case the currently bound texture id is already
+        // in use. (Shouldn't happen in Quake.)
+        // To Do: reclaim the old texture memory from the virtual memory.
+
+        evict(e);
+
+        e->alpha = alpha;
+        e->pData = mBase + mLength;
+        memcpy(e->pData, data, size);
+        e->size = size;
+        e->width = width;
+        e->height = height;
+        e->mipmap = mipmap;
+        e->real_texnum = -1;
+        mLength += size;
+
+        update(e);
+    }
+
+    // Re-upload the current textures because we've been reset.
+    void rebindAll() {
+      for(entry* e = mFirst; e; e = e->next ) {
+        if (e->real_texnum >= 0) {
+                glBindTexture(GL_TEXTURE_2D, e->real_texnum);
+                if (e->pData) {
+          GL_Upload8 (e->pData, e->width, e->height, e->mipmap,
+              e->alpha);
+                }
+        }
+      }
+    }
+
+private:
+
+    textureStore() {
+        mFirst = 0;
+        mLast = 0;
+        mTextureCount = 0;
+
+        char fullpath[MAX_OSPATH];
+        sprintf(fullpath, "%s/%s", com_gamedir, TEXTURE_STORE_NAME);
+
+        mFileId = open(fullpath, O_RDWR | O_CREAT, 0666);
+        if ( mFileId == -1 ) {
+            Sys_Error("Could not open texture store file %s: %d", fullpath,
+                    errno);
+        }
+
+        if (-1 == lseek(mFileId, TEXTURE_STORE_SIZE-1, SEEK_SET)) {
+            Sys_Error("Could not extend the texture store file size. %d",
+                    errno);
+        }
+        char end;
+        end = 0;
+        if (-1 == write(mFileId, &end, 1)) {
+            Sys_Error("Could not write last byte of the texture store file. %d",
+                    errno);
+        }
+
+        mBase = (byte*) mmap((caddr_t)0, TEXTURE_STORE_SIZE,
+                PROT_READ | PROT_WRITE, MAP_PRIVATE, mFileId, 0);
+
+        if (mBase == (byte*) -1) {
+            Sys_Error("Could not mmap file %s: %d", fullpath, errno);
+        }
+        mLength = 0;
+        mCapacity = TEXTURE_STORE_SIZE;
+        mRamUsed = 0;
+        mRamSize = LIVE_TEXTURE_LIMIT;
+    }
+
+    ~textureStore() {
+        munmap(mBase, mCapacity);
+        COM_CloseFile(mFileId);
+    }
+
+    void unlink(entry* e) {
+        if (e == mFirst) {
+            mFirst = e->next;
+        }
+        if (e == mLast) {
+            mLast = e->prev;
+        }
+        e->unlink();
+    }
+
+    void ensure(int size) {
+        while ( mRamSize - mRamUsed < (unsigned int) size) {
+            entry* e = mLast;
+            if(! e) {
+                Sys_Error("Ran out of entries");
+                return;
+            }
+            evict(e);
+        }
+        mRamUsed += size;
+    }
+
+    void evict(entry* e) {
+        unlink(e);
+        if ( e->pData ) {
+            glDeleteTextures(1, (unsigned int*) &e->real_texnum);
+            e->real_texnum = -1;
+            mRamUsed -= e->size;
+        }
+    }
+
+    static const size_t TEXTURE_STORE_SIZE = 16 * 1024 * 1024;
+    static const size_t LIVE_TEXTURE_LIMIT = 1 * 1024 * 1024;
+    static const size_t TEXTURE_STORE_NUM_TEXTURES = 512;
+
+    int mFileId;
+    byte* mBase;    // Base address of the memory mapped file
+    size_t mLength; // How much of the mm file we are currently using
+    size_t mCapacity; // Total size of the memory mapped file
+
+    // Keep track of texture RAM.
+    size_t mRamUsed;
+    size_t mRamSize;
+
+    // The virtual textures
+
+
+    entry mTextures[MAX_GLTEXTURES];
+    entry* mFirst; // LRU queue
+    entry* mLast;
+    size_t mTextureCount; // How many virtual textures have been allocated
+
+    static textureStore* g_pTextureCache;
+
+    int mBoundTextureID;
+};
+
+textureStore* textureStore::g_pTextureCache;
+
+#endif
+
+
+void GL_Bind (int texnum)
+{
+  if (gl_nobind.value)
+    texnum = char_texture;
+  if (currenttexture == texnum)
+    return;
+  currenttexture = texnum;
+#ifdef _WIN32
+  bindTexFunc (GL_TEXTURE_2D, texnum);
+#else
+
+#ifdef USE_TEXTURE_STORE
+     textureStore::get()->bind(texnum);
+#else
+  glBindTexture(GL_TEXTURE_2D, texnum);
+#endif
+
+#endif
+}
+
+
+/*
+=============================================================================
+
+  scrap allocation
+
+  Allocate all the little status bar obejcts into a single texture
+  to crutch up stupid hardware / drivers
+
+=============================================================================
+*/
+
+#define	MAX_SCRAPS		2
+#define	BLOCK_WIDTH		256
+#define	BLOCK_HEIGHT	256
+
+int			scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
+byte		scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
+qboolean	scrap_dirty;
+int			scrap_texnum;
+
+// returns a texture number and the position inside it
+int Scrap_AllocBlock (int w, int h, int *x, int *y)
+{
+  int		i, j;
+  int		best, best2;
+  int		bestx;
+  int		texnum;
+
+  for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
+  {
+    best = BLOCK_HEIGHT;
+
+    for (i=0 ; i<BLOCK_WIDTH-w ; i++)
+    {
+      best2 = 0;
+
+      for (j=0 ; j<w ; j++)
+      {
+        if (scrap_allocated[texnum][i+j] >= best)
+          break;
+        if (scrap_allocated[texnum][i+j] > best2)
+          best2 = scrap_allocated[texnum][i+j];
+      }
+      if (j == w)
+      {	// this is a valid spot
+        *x = i;
+        *y = best = best2;
+      }
+    }
+
+    if (best + h > BLOCK_HEIGHT)
+      continue;
+
+    for (i=0 ; i<w ; i++)
+      scrap_allocated[texnum][*x + i] = best + h;
+
+    return texnum;
+  }
+
+  Sys_Error ("Scrap_AllocBlock: full");
+  return 0;
+}
+
+int	scrap_uploads;
+
+void Scrap_Upload (void)
+{
+  int		texnum;
+
+  scrap_uploads++;
+
+  for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) {
+    GL_Bind(scrap_texnum + texnum);
+    GL_Upload8 (scrap_texels[texnum], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);
+  }
+  scrap_dirty = false;
+}
+
+//=============================================================================
+/* Support Routines */
+
+typedef struct cachepic_s
+{
+  char		name[MAX_QPATH];
+  qpic_t		pic;
+  byte		padding[32];	// for appended glpic
+} cachepic_t;
+
+#define	MAX_CACHED_PICS		128
+cachepic_t	menu_cachepics[MAX_CACHED_PICS];
+int			menu_numcachepics;
+
+byte		menuplyr_pixels[4096];
+
+int		pic_texels;
+int		pic_count;
+
+
+/*
+================
+GL_LoadPicTexture
+================
+*/
+int GL_LoadPicTexture (qpic_t *pic)
+{
+  return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true);
+}
+
+
+qpic_t *Draw_PicFromWad (const char *name)
+{
+    packedGlpic_t	*pp;
+
+  pp = (packedGlpic_t*) W_GetLumpName (name);
+
+  qpic_t* p = & pp->qpic;
+  glpic_t* gl = & pp->g.glpic;
+
+  // load little ones into the scrap
+  if (p->width < 64 && p->height < 64)
+  {
+    int		x, y;
+    int		i, j, k;
+    int		texnum;
+
+    texnum = Scrap_AllocBlock (p->width, p->height, &x, &y);
+    scrap_dirty = true;
+    k = 0;
+    for (i=0 ; i<p->height ; i++)
+      for (j=0 ; j<p->width ; j++, k++)
+        scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];
+    texnum += scrap_texnum;
+    gl->texnum = texnum;
+    gl->sl = (x+0.01)/(float)BLOCK_WIDTH;
+    gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;
+    gl->tl = (y+0.01)/(float)BLOCK_WIDTH;
+    gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;
+
+    pic_count++;
+    pic_texels += p->width*p->height;
+  }
+  else
+  {
+    gl->texnum = GL_LoadPicTexture (p);
+    gl->sl = 0;
+    gl->sh = 1;
+    gl->tl = 0;
+    gl->th = 1;
+  }
+  return p;
+}
+
+
+/*
+================
+Draw_CachePic
+================
+*/
+qpic_t	*Draw_CachePic (const char *path)
+{
+  cachepic_t	*pic;
+  int			i;
+  qpic_t		*dat;
+  glpic_t		*gl;
+
+  for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
+    if (!strcmp (path, pic->name))
+      return &pic->pic;
+
+  if (menu_numcachepics == MAX_CACHED_PICS)
+    Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
+  menu_numcachepics++;
+  strcpy (pic->name, path);
+
+//
+// load the pic from disk
+//
+  dat = (qpic_t *)COM_LoadTempFile (path);
+  if (!dat)
+    Sys_Error ("Draw_CachePic: failed to load %s", path);
+  SwapPic (dat);
+
+  // HACK HACK HACK --- we need to keep the bytes for
+  // the translatable player picture just for the menu
+  // configuration dialog
+  if (!strcmp (path, "gfx/menuplyr.lmp"))
+    memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
+
+  pic->pic.width = dat->width;
+  pic->pic.height = dat->height;
+
+  glpic_t temp;
+  gl = &temp;
+  gl->texnum = GL_LoadPicTexture (dat);
+  gl->sl = 0;
+  gl->sh = 1;
+  gl->tl = 0;
+  gl->th = 1;
+
+  memcpy(pic->pic.data, &temp, sizeof(temp));
+
+  return &pic->pic;
+}
+
+
+void Draw_CharToConback (int num, byte *dest)
+{
+  int		row, col;
+  byte	*source;
+  int		drawline;
+  int		x;
+
+  row = num>>4;
+  col = num&15;
+  source = draw_chars + (row<<10) + (col<<3);
+
+  drawline = 8;
+
+  while (drawline--)
+  {
+    for (x=0 ; x<8 ; x++)
+      if (source[x] != 255)
+        dest[x] = 0x60 + source[x];
+    source += 128;
+    dest += 320;
+  }
+
+}
+
+typedef struct
+{
+  const char *name;
+  int	minimize, maximize;
+} glmode_t;
+
+glmode_t modes[] = {
+  {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
+  {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
+  {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
+  {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
+  {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
+  {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
+};
+
+/*
+===============
+Draw_TextureMode_f
+===============
+*/
+void Draw_TextureMode_f (void)
+{
+  int		i;
+  gltexture_t	*glt;
+
+  if (Cmd_Argc() == 1)
+  {
+    for (i=0 ; i< 6 ; i++)
+      if (gl_filter_min == modes[i].minimize)
+      {
+        Con_Printf ("%s\n", modes[i].name);
+        return;
+      }
+    Con_Printf ("current filter is unknown???\n");
+    return;
+  }
+
+  for (i=0 ; i< 6 ; i++)
+  {
+    if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
+      break;
+  }
+  if (i == 6)
+  {
+    Con_Printf ("bad filter name\n");
+    return;
+  }
+
+  gl_filter_min = modes[i].minimize;
+  gl_filter_max = modes[i].maximize;
+
+  // change all the existing mipmap texture objects
+  for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+  {
+    if (glt->mipmap)
+    {
+      GL_Bind (glt->texnum);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+    }
+  }
+}
+
+/*
+===============
+Draw_Init
+===============
+*/
+void Draw_Init (void)
+{
+  int		i;
+  qpic_t	*cb;
+  byte	*dest, *src;
+  int		x, y;
+  char	ver[40];
+  glpic_t	*gl;
+  int		start;
+  byte	*ncdata;
+  int		f, fstep;
+
+
+  Cvar_RegisterVariable (&gl_nobind);
+  Cvar_RegisterVariable (&gl_max_size);
+  Cvar_RegisterVariable (&gl_picmip);
+
+  // 3dfx can only handle 256 wide textures
+  if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) ||
+    strstr((char *)gl_renderer, "Glide"))
+    Cvar_Set ("gl_max_size", "256");
+
+  Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
+
+  // load the console background and the charset
+  // by hand, because we need to write the version
+  // string into the background before turning
+  // it into a texture
+  draw_chars = (byte*) W_GetLumpName ("conchars");
+  for (i=0 ; i<256*64 ; i++)
+    if (draw_chars[i] == 0)
+      draw_chars[i] = 255;	// proper transparent color
+
+  // now turn them into textures
+  char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
+
+  start = Hunk_LowMark();
+
+  cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp");
+  if (!cb)
+    Sys_Error ("Couldn't load gfx/conback.lmp");
+  SwapPic (cb);
+
+  // hack the version number directly into the pic
+#if defined(__linux__)
+  sprintf (ver, "(Linux %2.2f, gl %4.2f) %4.2f", (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
+#else
+  sprintf (ver, "(gl %4.2f) %4.2f", (float)GLQUAKE_VERSION, (float)VERSION);
+#endif
+  dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver);
+  y = strlen(ver);
+  for (x=0 ; x<y ; x++)
+    Draw_CharToConback (ver[x], dest+(x<<3));
+
+#if 0
+  conback->width = vid.conwidth;
+  conback->height = vid.conheight;
+
+   // scale console to vid size
+   dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback");
+
+   for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth)
+   {
+     src = cb->data + cb->width * (y*cb->height/vid.conheight);
+     if (vid.conwidth == cb->width)
+       memcpy (dest, src, vid.conwidth);
+     else
+     {
+       f = 0;
+       fstep = cb->width*0x10000/vid.conwidth;
+       for (x=0 ; x<vid.conwidth ; x+=4)
+       {
+         dest[x] = src[f>>16];
+         f += fstep;
+         dest[x+1] = src[f>>16];
+         f += fstep;
+         dest[x+2] = src[f>>16];
+         f += fstep;
+         dest[x+3] = src[f>>16];
+         f += fstep;
+       }
+     }
+   }
+#else
+  conback->g.width = cb->width;
+  conback->g.height = cb->height;
+  ncdata = cb->data;
+#endif
+
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+  gl = &conback->g.glpic;
+  gl->texnum = GL_LoadTexture ("conback", conback->g.width, conback->g.height, ncdata, false, false);
+  gl->sl = 0;
+  gl->sh = 1;
+  gl->tl = 0;
+  gl->th = 1;
+  conback->g.width = vid.width;
+  conback->g.height = vid.height;
+
+  // free loaded console
+  Hunk_FreeToLowMark(start);
+
+  // save a texture slot for translated picture
+  translate_texture = texture_extension_number++;
+
+  // save slots for scraps
+  scrap_texnum = texture_extension_number;
+  texture_extension_number += MAX_SCRAPS;
+
+  //
+  // get the other pics we need
+  //
+  draw_disc = Draw_PicFromWad ("disc");
+  draw_backtile = Draw_PicFromWad ("backtile");
+}
+
+
+
+/*
+================
+Draw_Character
+
+Draws one 8*8 graphics character with 0 being transparent.
+It can be clipped to the top of the screen to allow the console to be
+smoothly scrolled off.
+================
+*/
+void Draw_Character (int x, int y, int num)
+{
+  byte			*dest;
+  byte			*source;
+  unsigned short	*pusdest;
+  int				drawline;
+  int				row, col;
+  float			frow, fcol, size;
+
+  if (num == 32)
+    return;		// space
+
+  num &= 255;
+
+  if (y <= -8)
+    return;			// totally off screen
+
+  row = num>>4;
+  col = num&15;
+
+  frow = row*0.0625;
+  fcol = col*0.0625;
+  size = 0.0625;
+
+  GL_Bind (char_texture);
+
+#ifdef USE_OPENGLES
+  DrawQuad(x, y, 8, 8, fcol, frow, size, size);
+#else
+  glBegin (GL_QUADS);
+  glTexCoord2f (fcol, frow);
+  glVertex2f (x, y);
+  glTexCoord2f (fcol + size, frow);
+  glVertex2f (x+8, y);
+  glTexCoord2f (fcol + size, frow + size);
+  glVertex2f (x+8, y+8);
+  glTexCoord2f (fcol, frow + size);
+  glVertex2f (x, y+8);
+  glEnd ();
+#endif
+}
+
+/*
+================
+Draw_String
+================
+*/
+void Draw_String (int x, int y, const char *str)
+{
+  while (*str)
+  {
+    Draw_Character (x, y, *str);
+    str++;
+    x += 8;
+  }
+}
+
+/*
+================
+Draw_DebugChar
+
+Draws a single character directly to the upper right corner of the screen.
+This is for debugging lockups by drawing different chars in different parts
+of the code.
+================
+*/
+void Draw_DebugChar (char num)
+{
+}
+
+/*
+=============
+Draw_AlphaPic
+=============
+*/
+void Draw_AlphaPic (int x, int y, packedGlpic_t *ppic, float alpha)
+{
+  byte			*dest, *source;
+  unsigned short	*pusdest;
+  int				v, u;
+  glpic_t			*gl;
+
+  if (scrap_dirty)
+    Scrap_Upload ();
+  gl = & ppic->g.glpic;
+  glDisable(GL_ALPHA_TEST);
+  glEnable (GL_BLEND);
+//	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+//	glCullFace(GL_FRONT);
+  glColor4f (1,1,1,alpha);
+  GL_Bind (gl->texnum);
+#ifdef USE_OPENGLES
+    DrawQuad(x, y, ppic->g.width, ppic->g.height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
+#else
+  glBegin (GL_QUADS);
+  glTexCoord2f (gl->sl, gl->tl);
+  glVertex2f (x, y);
+  glTexCoord2f (gl->sh, gl->tl);
+  glVertex2f (x+pic->width, y);
+  glTexCoord2f (gl->sh, gl->th);
+  glVertex2f (x+pic->width, y+pic->height);
+  glTexCoord2f (gl->sl, gl->th);
+  glVertex2f (x, y+pic->height);
+  glEnd ();
+#endif
+  glColor4f (1,1,1,1);
+  glEnable(GL_ALPHA_TEST);
+  glDisable (GL_BLEND);
+}
+
+
+/*
+=============
+Draw_Pic
+=============
+*/
+void Draw_Pic (int x, int y, qpic_t *pic)
+{
+  byte			*dest, *source;
+  unsigned short	*pusdest;
+  int				v, u;
+  glpic_t			*gl;
+
+  if (scrap_dirty)
+    Scrap_Upload ();
+  glpic_t temp;
+  memcpy(&temp, pic->data, sizeof(temp));
+  gl = & temp;
+  glColor4f (1,1,1,1);
+  GL_Bind (gl->texnum);
+#ifdef USE_OPENGLES
+    DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
+#else
+  glBegin (GL_QUADS);
+  glTexCoord2f (gl->sl, gl->tl);
+  glVertex2f (x, y);
+  glTexCoord2f (gl->sh, gl->tl);
+  glVertex2f (x+pic->width, y);
+  glTexCoord2f (gl->sh, gl->th);
+  glVertex2f (x+pic->width, y+pic->height);
+  glTexCoord2f (gl->sl, gl->th);
+  glVertex2f (x, y+pic->height);
+  glEnd ();
+#endif
+}
+
+
+/*
+=============
+Draw_TransPic
+=============
+*/
+void Draw_TransPic (int x, int y, qpic_t *pic)
+{
+  byte	*dest, *source, tbyte;
+  unsigned short	*pusdest;
+  int				v, u;
+
+  if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
+     (unsigned)(y + pic->height) > vid.height)
+  {
+    Sys_Error ("Draw_TransPic: bad coordinates");
+  }
+
+  Draw_Pic (x, y, pic);
+}
+
+
+/*
+=============
+Draw_TransPicTranslate
+
+Only used for the player color selection menu
+=============
+*/
+void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
+{
+  int				v, u, c;
+  unsigned		trans[64*64], *dest;
+  byte			*src;
+  int				p;
+
+  GL_Bind (translate_texture);
+
+  c = pic->width * pic->height;
+
+  dest = trans;
+  for (v=0 ; v<64 ; v++, dest += 64)
+  {
+    src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];
+    for (u=0 ; u<64 ; u++)
+    {
+      p = src[(u*pic->width)>>6];
+      if (p == 255)
+        dest[u] = p;
+      else
+        dest[u] =  d_8to24table[translation[p]];
+    }
+  }
+
+  glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+  glColor3f (1,1,1);
+#ifdef USE_OPENGLES
+    DrawQuad(x, y, pic->width, pic->height, 0, 0, 1, 1);
+#else
+  glBegin (GL_QUADS);
+  glTexCoord2f (0, 0);
+  glVertex2f (x, y);
+  glTexCoord2f (1, 0);
+  glVertex2f (x+pic->width, y);
+  glTexCoord2f (1, 1);
+  glVertex2f (x+pic->width, y+pic->height);
+  glTexCoord2f (0, 1);
+  glVertex2f (x, y+pic->height);
+  glEnd ();
+#endif
+}
+
+
+/*
+================
+Draw_ConsoleBackground
+
+================
+*/
+void Draw_ConsoleBackground (int lines)
+{
+  int y = (vid.height * 3) >> 2;
+
+  if (lines > y)
+    Draw_Pic(0, lines - vid.height, &conback->qpic);
+  else
+    Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
+}
+
+
+/*
+=============
+Draw_TileClear
+
+This repeats a 64*64 tile graphic to fill the screen around a sized down
+refresh window.
+=============
+*/
+
+typedef union ByteToInt_t {
+    byte b[4];
+    int i;
+} ByteToInt;
+
+void Draw_TileClear (int x, int y, int w, int h)
+{
+  glColor3f (1,1,1);
+  ByteToInt b;
+  memcpy(b.b, draw_backtile->data, sizeof(b.b));
+  GL_Bind (b.i);
+#ifdef USE_OPENGLES
+  DrawQuad(x, y, w, h, x/64.0, y/64.0, w/64.0, h/64.0);
+#else
+  glBegin (GL_QUADS);
+  glTexCoord2f (x/64.0, y/64.0);
+  glVertex2f (x, y);
+  glTexCoord2f ( (x+w)/64.0, y/64.0);
+  glVertex2f (x+w, y);
+  glTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
+  glVertex2f (x+w, y+h);
+  glTexCoord2f ( x/64.0, (y+h)/64.0 );
+  glVertex2f (x, y+h);
+  glEnd ();
+#endif
+}
+
+
+/*
+=============
+Draw_Fill
+
+Fills a box of pixels with a single color
+=============
+*/
+void Draw_Fill (int x, int y, int w, int h, int c)
+{
+  glDisable (GL_TEXTURE_2D);
+  glColor3f (host_basepal[c*3]/255.0,
+    host_basepal[c*3+1]/255.0,
+    host_basepal[c*3+2]/255.0);
+
+#ifdef USE_OPENGLES
+  DrawQuad_NoTex(x, y, w, h);
+#else
+  glBegin (GL_QUADS);
+
+  glVertex2f (x,y);
+  glVertex2f (x+w, y);
+  glVertex2f (x+w, y+h);
+  glVertex2f (x, y+h);
+
+  glEnd ();
+#endif
+  glColor3f (1,1,1);
+  glEnable (GL_TEXTURE_2D);
+}
+//=============================================================================
+
+/*
+================
+Draw_FadeScreen
+
+================
+*/
+void Draw_FadeScreen (void)
+{
+  glEnable (GL_BLEND);
+  glDisable (GL_TEXTURE_2D);
+  glColor4f (0, 0, 0, 0.8);
+#ifdef USE_OPENGLES
+  DrawQuad_NoTex(0, 0, vid.width, vid.height);
+#else
+  glBegin (GL_QUADS);
+
+  glVertex2f (0,0);
+  glVertex2f (vid.width, 0);
+  glVertex2f (vid.width, vid.height);
+  glVertex2f (0, vid.height);
+
+  glEnd ();
+#endif
+  glColor4f (1,1,1,1);
+  glEnable (GL_TEXTURE_2D);
+  glDisable (GL_BLEND);
+
+  Sbar_Changed();
+}
+
+//=============================================================================
+
+/*
+================
+Draw_BeginDisc
+
+Draws the little blue disc in the corner of the screen.
+Call before beginning any disc IO.
+================
+*/
+void Draw_BeginDisc (void)
+{
+  if (!draw_disc)
+    return;
+#ifdef USE_OPENGLES
+  // !!! Implement this
+#else
+  glDrawBuffer  (GL_FRONT);
+  Draw_Pic (vid.width - 24, 0, draw_disc);
+  glDrawBuffer  (GL_BACK);
+#endif
+}
+
+
+/*
+================
+Draw_EndDisc
+
+Erases the disc icon.
+Call after completing any disc IO
+================
+*/
+void Draw_EndDisc (void)
+{
+}
+
+/*
+================
+GL_Set2D
+
+Setup as if the screen was 320*200
+================
+*/
+void GL_Set2D (void)
+{
+  glViewport (glx, gly, glwidth, glheight);
+
+  glMatrixMode(GL_PROJECTION);
+    glLoadIdentity ();
+#ifdef USE_OPENGLES
+  glOrthof (0, vid.width, vid.height, 0, -99999, 99999);
+#else
+  glOrtho  (0, vid.width, vid.height, 0, -99999, 99999);
+#endif
+
+  glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity ();
+
+  glDisable (GL_DEPTH_TEST);
+  glDisable (GL_CULL_FACE);
+  glDisable (GL_BLEND);
+  glEnable (GL_ALPHA_TEST);
+//	glDisable (GL_ALPHA_TEST);
+
+  glColor4f (1,1,1,1);
+}
+
+//====================================================================
+
+/*
+================
+GL_FindTexture
+================
+*/
+int GL_FindTexture (const char *identifier)
+{
+  int		i;
+  gltexture_t	*glt;
+
+  for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+  {
+    if (!strcmp (identifier, glt->identifier))
+      return gltextures[i].texnum;
+  }
+
+  return -1;
+}
+
+/*
+================
+GL_ResampleTexture
+================
+*/
+void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight)
+{
+  int		i, j;
+  unsigned	*inrow;
+  unsigned	frac, fracstep;
+
+  fracstep = inwidth*0x10000/outwidth;
+  for (i=0 ; i<outheight ; i++, out += outwidth)
+  {
+    inrow = in + inwidth*(i*inheight/outheight);
+    frac = fracstep >> 1;
+    for (j=0 ; j<outwidth ; j+=4)
+    {
+      out[j] = inrow[frac>>16];
+      frac += fracstep;
+      out[j+1] = inrow[frac>>16];
+      frac += fracstep;
+      out[j+2] = inrow[frac>>16];
+      frac += fracstep;
+      out[j+3] = inrow[frac>>16];
+      frac += fracstep;
+    }
+  }
+}
+
+/*
+================
+GL_Resample8BitTexture -- JACK
+================
+*/
+void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out,  int outwidth, int outheight)
+{
+  int		i, j;
+  unsigned	char *inrow;
+  unsigned	frac, fracstep;
+
+  fracstep = inwidth*0x10000/outwidth;
+  for (i=0 ; i<outheight ; i++, out += outwidth)
+  {
+    inrow = in + inwidth*(i*inheight/outheight);
+    frac = fracstep >> 1;
+    for (j=0 ; j<outwidth ; j+=4)
+    {
+      out[j] = inrow[frac>>16];
+      frac += fracstep;
+      out[j+1] = inrow[frac>>16];
+      frac += fracstep;
+      out[j+2] = inrow[frac>>16];
+      frac += fracstep;
+      out[j+3] = inrow[frac>>16];
+      frac += fracstep;
+    }
+  }
+}
+
+
+/*
+================
+GL_MipMap
+
+Operates in place, quartering the size of the texture
+================
+*/
+void GL_MipMap (byte *in, int width, int height)
+{
+  int		i, j;
+  byte	*out;
+
+  width <<=2;
+  height >>= 1;
+  out = in;
+  for (i=0 ; i<height ; i++, in+=width)
+  {
+    for (j=0 ; j<width ; j+=8, out+=4, in+=8)
+    {
+      out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
+      out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
+      out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
+      out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
+    }
+  }
+}
+
+#ifdef SUPPORT_8BIT_MIPMAPGENERATION
+/*
+================
+GL_MipMap8Bit
+
+Mipping for 8 bit textures
+
+The "in" and "out" arguments can point to the same buffer if desired
+================
+*/
+void GL_MipMap8Bit (byte *in, byte* out, int width, int height)
+{
+  int		i, j;
+  unsigned short     r,g,b;
+  byte	*at1, *at2, *at3, *at4;
+
+//	width <<=2;
+  height >>= 1;
+  for (i=0 ; i<height ; i++, in+=width)
+  {
+    for (j=0 ; j<width ; j+=2, out+=1, in+=2)
+    {
+      at1 = (byte *) (d_8to24table + in[0]);
+      at2 = (byte *) (d_8to24table + in[1]);
+      at3 = (byte *) (d_8to24table + in[width+0]);
+      at4 = (byte *) (d_8to24table + in[width+1]);
+
+       r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
+       g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
+       b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
+
+      out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
+    }
+  }
+}
+
+#endif // SUPPORT_8BIT_MIPMAPGENERATION
+
+void glTexImage2DHelper( GLenum target,
+   GLint level,
+   GLint internalformat,
+   GLsizei width,
+   GLsizei height,
+   GLint border,
+   GLenum format,
+   GLenum type,
+   const GLvoid *pixels )
+{
+  // In full OpenGL The internalformat can be 1..4, to indicate how many components of the data are valid.
+  // OpenGL ES requires the internalformat argument match the format for glTexImage2D.
+
+  glTexImage2D(target, level, format, width, height, border, format, type, pixels);
+}
+
+
+// Uncomment to enable manual MipMap generation
+#define USE_MANUAL_MIPMAP_GEN
+
+// Uncomment one of the following:
+
+// #define USE_16BPP_WITH_8888_ALPHA
+// #define USE_16BPP_WITH_5551_ALPHA // <--- This has bugs on the simulator and the device. (Device has all alpha images invisible.)
+#define USE_16BPP_WITH_4444_ALPHA // <--- This has bugs on the simulator, works in device
+// #define USE_32BPP
+// #define USE_32BPP_MANUAL_MIPMAP_GEN
+
+#ifdef USE_MANUAL_MIPMAP_GEN
+
+inline unsigned int average4(unsigned int a, unsigned int b,
+        unsigned int c, unsigned int d,
+        unsigned int shift, unsigned int mask) {
+    unsigned int aElem = (a >> shift) & mask;
+    unsigned int bElem = (b >> shift) & mask;
+    unsigned int cElem = (c >> shift) & mask;
+    unsigned int dElem = (d >> shift) & mask;
+    unsigned int avgElem = ((aElem + bElem + cElem + dElem) >> 2) & mask;
+    return avgElem << shift;
+}
+
+inline unsigned int average2(unsigned int a, unsigned int b,
+        unsigned int shift, unsigned int mask) {
+    unsigned int aElem = (a >> shift) & mask;
+    unsigned int bElem = (b >> shift) & mask;
+    unsigned int avgElem = ((aElem + bElem) >> 1) & mask;
+    return avgElem << shift;
+}
+
+inline unsigned int average4444(unsigned int a, unsigned int b) {
+    return
+        average2(a,b,0,0xf) |
+        average2(a,b,4,0xf) |
+        average2(a,b,8,0xf) |
+        average2(a,b,12,0xf);
+}
+
+inline unsigned int average565(unsigned int a, unsigned int b) {
+    return
+        average2(a,b,0,0x1f) |
+        average2(a,b,5,0x3f) |
+        average2(a,b,11,0x1f);
+}
+
+inline unsigned int average2_8888(unsigned int a, unsigned int b) {
+    return
+        average2(a,b,0,0xff) |
+        average2(a,b,8,0xff) |
+        average2(a,b,16,0xff) |
+        average2(a,b,24,0xff);
+}
+
+inline unsigned int average4_8888(unsigned int a, unsigned int b,
+        unsigned int c, unsigned int d) {
+    return
+        average4(a,b,c,d,0,0xff) |
+        average4(a,b,c,d,8,0xff) |
+        average4(a,b,c,d,16,0xff) |
+        average4(a,b,c,d,24,0xff);
+}
+
+#endif
+
+// pData is 8 bpp 32-bit color
+
+void sendTexture(int mipLevel, int width, int height, unsigned int* pData, qboolean alpha) {
+    if (alpha) {
+#if defined(USE_16BPP_WITH_8888_ALPHA)
+        // 8888
+        glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
+#elif defined(USE_16BPP_WITH_5551_ALPHA)
+        // 5551
+        glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 0);
+        glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
+#else
+        // 4444
+        glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
+        glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
+#endif
+    }
+    else {
+#if 0
+        // 8888
+        glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
+#else
+        // 565
+        glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
+        glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
+#endif
+    }
+}
+
+/*
+===============
+GL_Upload32
+===============
+*/
+void GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap, qboolean alpha)
+{
+  int			samples;
+static	unsigned	scaled[1024*512];	// [512*256];
+  int			scaled_width, scaled_height;
+
+  for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+    ;
+  for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+    ;
+
+  scaled_width >>= (int)gl_picmip.value;
+  scaled_height >>= (int)gl_picmip.value;
+
+  if (scaled_width > gl_max_size.value)
+    scaled_width = (int) gl_max_size.value;
+  if (scaled_height > gl_max_size.value)
+    scaled_height = (int) gl_max_size.value;
+
+  if (scaled_width * scaled_height > (int) sizeof(scaled)/4)
+    Sys_Error ("GL_LoadTexture: too big");
+
+  samples = alpha ? gl_alpha_format : gl_solid_format;
+
+    texels += scaled_width * scaled_height;
+
+  if (scaled_width == width && scaled_height == height)
+  {
+#if 0 // Disable this optimization, we want to be able to easily switch texture formats
+    if (!mipmap)
+    {
+      glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+      goto done;
+    }
+#endif
+    memcpy (scaled, data, width*height*4);
+  }
+  else
+    GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
+
+#if defined(USE_16BPP_WITH_8888_ALPHA) || defined(USE_16BPP_WITH_5551_ALPHA) || defined(USE_16BPP_WITH_4444_ALPHA)
+  // Upload as 16 bpp
+
+#ifdef USE_MANUAL_MIPMAP_GEN
+#else
+  // Use automatic MIPMAP generation
+  if (mipmap)
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
+  }
+#endif
+
+  sendTexture(0, scaled_width, scaled_height, scaled, alpha);
+
+#ifdef USE_MANUAL_MIPMAP_GEN
+  if (mipmap) {
+      // Compute mip levels
+      int mipWidth = scaled_width;
+      int mipHeight = scaled_height;
+      int mipLevel = 1;
+      while (mipWidth > 1 || mipHeight > 1) {
+          if (mipWidth > 1 && mipHeight > 1) {
+              // Scale horizontally and vertically
+              int srcWidth = mipWidth;
+                mipWidth >>= 1;
+                mipHeight >>= 1;
+                const unsigned int* pIn = (const unsigned int*) scaled;
+                unsigned int* pOut = (unsigned int*) scaled;
+                for(int y = 0; y < mipHeight; y++) {
+                    for (int x = 0; x < mipWidth; x++) {
+                        *pOut++ = average4_8888(pIn[0], pIn[1],
+                                pIn[srcWidth], pIn[srcWidth+1]);
+                        pIn += 2;
+                    }
+                    pIn += srcWidth;
+                }
+          }
+          else {
+              // Scale horizontally:
+              if (mipWidth > 1) {
+                  mipWidth >>= 1;
+                  const unsigned int* pIn = (const unsigned int*) scaled;
+                  unsigned int* pOut = (unsigned int*) scaled;
+                  unsigned int numTexels = mipHeight * mipWidth;
+                  for(unsigned int i = 0; i < numTexels; i++) {
+                      *pOut++ = average2_8888(pIn[0], pIn[1]);
+                      pIn += 2;
+                  }
+              }
+              // Scale vertically:
+              if (mipHeight > 1) {
+                  mipHeight >>= 1;
+                  const unsigned int* pIn = (const unsigned int*) scaled;
+                  unsigned int* pOut = (unsigned int*) scaled;
+                  for(int y = 0; y < mipHeight; y++) {
+                      for (int x = 0; x < mipWidth; x++) {
+                          *pOut++ = average2_8888(pIn[0], pIn[mipWidth]);
+                          pIn += 1;
+                      }
+                      pIn += mipWidth;
+                  }
+              }
+          }
+
+          sendTexture(mipLevel, mipWidth, mipHeight, scaled, alpha);
+          mipLevel++;
+      }
+  }
+
+#else
+  if (mipmap)
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0);
+  }
+#endif
+
+#elif defined(USE_32BPP)
+  // 8888
+  // Use automatic MIPMAP generation
+  if (mipmap)
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
+  }
+  glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+  if (mipmap)
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0);
+  }
+#else
+  glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+  if (mipmap)
+  {
+    int		miplevel;
+
+    miplevel = 0;
+    while (scaled_width > 1 || scaled_height > 1)
+    {
+      GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
+      scaled_width >>= 1;
+      scaled_height >>= 1;
+      if (scaled_width < 1)
+        scaled_width = 1;
+      if (scaled_height < 1)
+        scaled_height = 1;
+      miplevel++;
+      glTexImage2DHelper (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
+    }
+  }
+#endif
+done: ;
+
+  if (mipmap)
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+  }
+  else
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+  }
+}
+
+#ifdef USE_OPENGLES
+
+void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
+{
+  int			i, s, bytesUsed;
+  qboolean	noalpha;
+  int			p;
+  static unsigned j;
+    static	unsigned char compressedTextureBuffer[1024*512];	// [512*256];
+  unsigned char* pTex = compressedTextureBuffer;
+  int			scaled_width, scaled_height;
+  int miplevel = 0;
+
+  int originalScaledWidth;
+  int originalScaledHeight;
+
+  s = width*height;
+  // if there are no transparent pixels, make it a 3 component
+  // texture even if it was specified as otherwise
+  if (alpha)
+  {
+    noalpha = true;
+    for (i=0 ; i<s ; i++)
+    {
+      if (data[i] == 255)
+        noalpha = false;
+    }
+
+    if (alpha && noalpha)
+      alpha = false;
+  }
+  for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+    ;
+  for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+    ;
+
+  scaled_width >>= (int)gl_picmip.value;
+  scaled_height >>= (int)gl_picmip.value;
+
+  if (scaled_width > gl_max_size.value)
+    scaled_width = (int) gl_max_size.value;
+  if (scaled_height > gl_max_size.value)
+    scaled_height = (int) gl_max_size.value;
+
+  if (scaled_width * scaled_height > ((int) (sizeof(compressedTextureBuffer) * 3 / 4)))
+    Sys_Error ("GL_LoadTexture: too big");
+
+  // Copy the palette
+
+  int entrySize = alpha ? 4 : 3;
+  int paletteSize = entrySize * 256;
+  {
+    byte* pDest = compressedTextureBuffer;
+    const byte* pSrc = host_basepal;
+    if(alpha)
+    {
+      for(int i = 0; i< 255; i++)
+      {
+        *pDest++ = *pSrc++;
+        *pDest++ = *pSrc++;
+        *pDest++ = *pSrc++;
+        *pDest++ = 0xff;
+      }
+      // Entry 255 is transparent
+      *pDest++ = 0x00;
+      *pDest++ = 0x00;
+      *pDest++ = 0x00;
+      *pDest++ = 0x00;
+    }
+    else
+    {
+      memcpy(pDest, pSrc, paletteSize);
+    }
+  }
+
+  bytesUsed = paletteSize;
+  pTex += paletteSize;
+
+  texels += scaled_width * scaled_height;
+
+  if (scaled_width == width && scaled_height == height)
+  {
+    memcpy (pTex, data, scaled_width*scaled_height);
+  }
+  else
+    GL_Resample8BitTexture (data, width, height, pTex, scaled_width, scaled_height);
+
+  bytesUsed += scaled_width * scaled_height;
+
+  miplevel = 0;
+
+  originalScaledWidth = scaled_width;
+  originalScaledHeight = scaled_height;
+
+  if (mipmap)
+  {
+#ifdef SUPPORT_8BIT_MIPMAPGENERATION
+        miplevel = 1;
+    while (scaled_width > 1 || scaled_height > 1)
+    {
+      byte* pDest = (byte*) pTex + scaled_width * scaled_height;
+      GL_MipMap8Bit ((byte *)pTex, pDest, scaled_width, scaled_height);
+      pTex = pDest;
+      scaled_width >>= 1;
+      scaled_height >>= 1;
+      if (scaled_width < 1)
+        scaled_width = 1;
+      if (scaled_height < 1)
+        scaled_height = 1;
+      bytesUsed += scaled_width * scaled_height;
+      miplevel++;
+    }
+#else
+  Sys_Error("Unsupported attempt to generate 8 bit mip mapped texture. #define SUPPORT_8BIT_MIPMAPGENERATION");
+#endif
+  }
+
+  GLint internalFormat = alpha ? GL_PALETTE8_RGBA8_OES : GL_PALETTE8_RGB8_OES;
+  glCompressedTexImage2D (GL_TEXTURE_2D, -miplevel, internalFormat,
+            originalScaledWidth, originalScaledHeight,
+            0, bytesUsed, compressedTextureBuffer);
+
+  if (mipmap)
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+  }
+  else
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+  }
+}
+
+#else
+
+void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
+{
+  int			i, s;
+  qboolean	noalpha;
+  int			p;
+  static unsigned j;
+  int			samples;
+    static	unsigned char scaled[1024*512];	// [512*256];
+  int			scaled_width, scaled_height;
+
+  s = width*height;
+  // if there are no transparent pixels, make it a 3 component
+  // texture even if it was specified as otherwise
+  if (alpha)
+  {
+    noalpha = true;
+    for (i=0 ; i<s ; i++)
+    {
+      if (data[i] == 255)
+        noalpha = false;
+    }
+
+    if (alpha && noalpha)
+      alpha = false;
+  }
+  for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
+    ;
+  for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
+    ;
+
+  scaled_width >>= (int)gl_picmip.value;
+  scaled_height >>= (int)gl_picmip.value;
+
+  if (scaled_width > gl_max_size.value)
+    scaled_width = gl_max_size.value;
+  if (scaled_height > gl_max_size.value)
+    scaled_height = gl_max_size.value;
+
+  if (scaled_width * scaled_height > (int) sizeof(scaled))
+    Sys_Error ("GL_LoadTexture: too big");
+
+  samples = 1; // alpha ? gl_alpha_format : gl_solid_format;
+
+  texels += scaled_width * scaled_height;
+
+  if (scaled_width == width && scaled_height == height)
+  {
+    if (!mipmap)
+    {
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
+      goto done;
+    }
+    memcpy (scaled, data, width*height);
+  }
+  else
+    GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
+
+  glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled);
+  if (mipmap)
+  {
+#ifdef SUPPORT_8BIT_MIPMAPGENERATION
+    int		miplevel;
+
+    miplevel = 0;
+    while (scaled_width > 1 || scaled_height > 1)
+    {
+      GL_MipMap8Bit ((byte *)scaled, (byte*) scaled, scaled_width, scaled_height);
+      scaled_width >>= 1;
+      scaled_height >>= 1;
+      if (scaled_width < 1)
+        scaled_width = 1;
+      if (scaled_height < 1)
+        scaled_height = 1;
+      miplevel++;
+      glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
+    }
+#else
+  Sys_Error("Unsupported attept to generate 8 bit mip mapped texture.");
+#endif
+  }
+done: ;
+
+
+  if (mipmap)
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+  }
+  else
+  {
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+  }
+}
+
+#endif // ! OPENGL_ES
+
+/*
+===============
+GL_Upload8
+===============
+*/
+void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
+{
+static	unsigned	trans[640*480];		// FIXME, temporary
+  int			i, s;
+  qboolean	noalpha;
+  int			p;
+
+  s = width*height;
+  // if there are no transparent pixels, make it a 3 component
+  // texture even if it was specified as otherwise
+  if (alpha)
+  {
+    noalpha = true;
+    for (i=0 ; i<s ; i++)
+    {
+      p = data[i];
+      if (p == 255)
+        noalpha = false;
+      trans[i] = d_8to24table[p];
+    }
+
+    if (alpha && noalpha)
+      alpha = false;
+  }
+  else
+  {
+    if (s&3)
+      Sys_Error ("GL_Upload8: s&3");
+    for (i=0 ; i<s ; i+=4)
+    {
+      trans[i] = d_8to24table[data[i]];
+      trans[i+1] = d_8to24table[data[i+1]];
+      trans[i+2] = d_8to24table[data[i+2]];
+      trans[i+3] = d_8to24table[data[i+3]];
+    }
+  }
+
+   if (VID_Is8bit() && (data!=scrap_texels[0])
+#if !defined(USE_OPENGLES)
+    && !alpha
+#endif
+  ) {
+     GL_Upload8_EXT (data, width, height, mipmap, alpha);
+     return;
+  }
+  GL_Upload32 (trans, width, height, mipmap, alpha);
+}
+
+/*
+================
+GL_LoadTexture
+================
+*/
+int GL_LoadTexture (const char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha)
+{
+  qboolean	noalpha;
+  int			i, p, s;
+  gltexture_t	*glt;
+
+  // see if the texture is allready present
+  if (identifier[0])
+  {
+    for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+    {
+      if (!strcmp (identifier, glt->identifier))
+      {
+        if (width != glt->width || height != glt->height)
+          Sys_Error ("GL_LoadTexture: cache mismatch");
+        return gltextures[i].texnum;
+      }
+    }
+#ifdef USE_OPENGLES
+    // Surely we want to remember this new texture.
+    // Doing this costs 1% fps per timedemo on a DX7 PC,
+    // probably because of the linear search through the
+    // texture cache, but it saves 10 MB of VM growth per
+    // level load. It also makes the GL_TEXTUREMODE
+    // console command work correctly.
+    numgltextures++;
+#endif
+  }
+  else {
+    glt = &gltextures[numgltextures];
+    numgltextures++;
+  }
+
+  strcpy (glt->identifier, identifier);
+  glt->texnum = texture_extension_number;
+  glt->width = width;
+  glt->height = height;
+  glt->mipmap = mipmap;
+
+    GL_Bind(texture_extension_number);
+
+#ifdef USE_TEXTURE_STORE
+
+  textureStore::get()->create(width, height, data, mipmap, alpha);
+
+#else
+
+    GL_Upload8 (data, width, height, mipmap, alpha);
+
+#endif
+
+  texture_extension_number++;
+  return texture_extension_number-1;
+}
+
+
+/****************************************/
+
+static GLenum oldtarget = TEXTURE0_SGIS;
+
+void GL_SelectTexture (GLenum target)
+{
+  if (!gl_mtexable)
+    return;
+#ifdef USE_OPENGLES
+  glActiveTexture(target);
+#else
+  qglSelectTextureSGIS(target);
+#endif
+  if (target == oldtarget)
+    return;
+  cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture;
+  currenttexture = cnttextures[target-TEXTURE0_SGIS];
+  oldtarget = target;
+}
+
+// OpenGL ES compatible DrawQuad utility
+
+#define BEGIN_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+#define END_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+void DrawQuad_NoTex(float x, float y, float w, float h)
+{
+  BEGIN_QUAD
+
+  float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
+  short index[4] = {0, 1, 2, 3};
+  glVertexPointer( 2, GL_FLOAT, 0, vertex);
+  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+  glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index);
+  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+  END_QUAD
+}
+
+void DrawQuad(float x, float y, float w, float h, float u, float v, float uw, float vh)
+{
+  BEGIN_QUAD
+
+    float texcoord[2*4] = {u, v, u + uw, v, u + uw, v + vh, u, v + vh};
+  float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
+  unsigned short index[4] = {0, 1, 2, 3};
+  glTexCoordPointer( 2, GL_FLOAT, 0, texcoord);
+  glVertexPointer( 2, GL_FLOAT, 0, vertex);
+  glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index);
+
+  END_QUAD
+}
+
+#ifdef USE_OPENGLES
+
+// Reimplementation of OpenGL functions that are missing in OpenGL ES
+
+void glColor3f(GLfloat r, GLfloat g, GLfloat b)
+{
+  glColor4f(r, g, b, 1.0f);
+}
+
+void glColor4fv(GLfloat* pColor)
+{
+  glColor4f(pColor[0], pColor[1], pColor[2], pColor[3]);
+}
+
+float gVertexBuffer[VERTEXARRAYSIZE];
+float gColorBuffer[VERTEXARRAYSIZE];
+float gTexCoordBuffer[VERTEXARRAYSIZE];
+
+// Called when we've lost the OpenGL context and have to recreate it.
+extern void GL_Init();
+extern void R_InitParticleTexture2();
+extern void GL_UploadLightmaps();
+extern void R_ReloadSky();
+
+void GL_ReInit() {
+  GL_Init();
+  textureStore::get()->rebindAll();
+  scrap_dirty = true;
+  R_InitParticleTexture2();
+  GL_UploadLightmaps();
+  R_ReloadSky();
+}
+
+#endif
diff --git a/quake/src/WinQuake/gl_mesh.c b/quake/src/WinQuake/gl_mesh.cpp
old mode 100644
new mode 100755
similarity index 95%
rename from quake/src/WinQuake/gl_mesh.c
rename to quake/src/WinQuake/gl_mesh.cpp
index a5ff847..ecb753a
--- a/quake/src/WinQuake/gl_mesh.c
+++ b/quake/src/WinQuake/gl_mesh.cpp
@@ -1,360 +1,367 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// gl_mesh.c: triangle model functions

-

-#include "quakedef.h"

-

-/*

-=================================================================

-

-ALIAS MODEL DISPLAY LIST GENERATION

-

-=================================================================

-*/

-

-model_t		*aliasmodel;

-aliashdr_t	*paliashdr;

-

-qboolean	used[8192];

-

-// the command list holds counts and s/t values that are valid for

-// every frame

-int		commands[8192];

-int		numcommands;

-

-// all frames will have their vertexes rearranged and expanded

-// so they are in the order expected by the command list

-int		vertexorder[8192];

-int		numorder;

-

-int		allverts, alltris;

-

-int		stripverts[128];

-int		striptris[128];

-int		stripcount;

-

-/*

-================

-StripLength

-================

-*/

-int	StripLength (int starttri, int startv)

-{

-	int			m1, m2;

-	int			j;

-	mtriangle_t	*last, *check;

-	int			k;

-

-	used[starttri] = 2;

-

-	last = &triangles[starttri];

-

-	stripverts[0] = last->vertindex[(startv)%3];

-	stripverts[1] = last->vertindex[(startv+1)%3];

-	stripverts[2] = last->vertindex[(startv+2)%3];

-

-	striptris[0] = starttri;

-	stripcount = 1;

-

-	m1 = last->vertindex[(startv+2)%3];

-	m2 = last->vertindex[(startv+1)%3];

-

-	// look for a matching triangle

-nexttri:

-	for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)

-	{

-		if (check->facesfront != last->facesfront)

-			continue;

-		for (k=0 ; k<3 ; k++)

-		{

-			if (check->vertindex[k] != m1)

-				continue;

-			if (check->vertindex[ (k+1)%3 ] != m2)

-				continue;

-

-			// this is the next part of the fan

-

-			// if we can't use this triangle, this tristrip is done

-			if (used[j])

-				goto done;

-

-			// the new edge

-			if (stripcount & 1)

-				m2 = check->vertindex[ (k+2)%3 ];

-			else

-				m1 = check->vertindex[ (k+2)%3 ];

-

-			stripverts[stripcount+2] = check->vertindex[ (k+2)%3 ];

-			striptris[stripcount] = j;

-			stripcount++;

-

-			used[j] = 2;

-			goto nexttri;

-		}

-	}

-done:

-

-	// clear the temp used flags

-	for (j=starttri+1 ; j<pheader->numtris ; j++)

-		if (used[j] == 2)

-			used[j] = 0;

-

-	return stripcount;

-}

-

-/*

-===========

-FanLength

-===========

-*/

-int	FanLength (int starttri, int startv)

-{

-	int		m1, m2;

-	int		j;

-	mtriangle_t	*last, *check;

-	int		k;

-

-	used[starttri] = 2;

-

-	last = &triangles[starttri];

-

-	stripverts[0] = last->vertindex[(startv)%3];

-	stripverts[1] = last->vertindex[(startv+1)%3];

-	stripverts[2] = last->vertindex[(startv+2)%3];

-

-	striptris[0] = starttri;

-	stripcount = 1;

-

-	m1 = last->vertindex[(startv+0)%3];

-	m2 = last->vertindex[(startv+2)%3];

-

-

-	// look for a matching triangle

-nexttri:

-	for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)

-	{

-		if (check->facesfront != last->facesfront)

-			continue;

-		for (k=0 ; k<3 ; k++)

-		{

-			if (check->vertindex[k] != m1)

-				continue;

-			if (check->vertindex[ (k+1)%3 ] != m2)

-				continue;

-

-			// this is the next part of the fan

-

-			// if we can't use this triangle, this tristrip is done

-			if (used[j])

-				goto done;

-

-			// the new edge

-			m2 = check->vertindex[ (k+2)%3 ];

-

-			stripverts[stripcount+2] = m2;

-			striptris[stripcount] = j;

-			stripcount++;

-

-			used[j] = 2;

-			goto nexttri;

-		}

-	}

-done:

-

-	// clear the temp used flags

-	for (j=starttri+1 ; j<pheader->numtris ; j++)

-		if (used[j] == 2)

-			used[j] = 0;

-

-	return stripcount;

-}

-

-

-/*

-================

-BuildTris

-

-Generate a list of trifans or strips

-for the model, which holds for all frames

-================

-*/

-void BuildTris (void)

-{

-	int		i, j, k;

-	int		startv;

-	mtriangle_t	*last, *check;

-	int		m1, m2;

-	int		striplength;

-	trivertx_t	*v;

-	mtriangle_t *tv;

-	float	s, t;

-	int		index;

-	int		len, bestlen, besttype;

-	int		bestverts[1024];

-	int		besttris[1024];

-	int		type;

-

-	//

-	// build tristrips

-	//

-	numorder = 0;

-	numcommands = 0;

-	memset (used, 0, sizeof(used));

-	for (i=0 ; i<pheader->numtris ; i++)

-	{

-		// pick an unused triangle and start the trifan

-		if (used[i])

-			continue;

-

-		bestlen = 0;

-		for (type = 0 ; type < 2 ; type++)

-//	type = 1;

-		{

-			for (startv =0 ; startv < 3 ; startv++)

-			{

-				if (type == 1)

-					len = StripLength (i, startv);

-				else

-					len = FanLength (i, startv);

-				if (len > bestlen)

-				{

-					besttype = type;

-					bestlen = len;

-					for (j=0 ; j<bestlen+2 ; j++)

-						bestverts[j] = stripverts[j];

-					for (j=0 ; j<bestlen ; j++)

-						besttris[j] = striptris[j];

-				}

-			}

-		}

-

-		// mark the tris on the best strip as used

-		for (j=0 ; j<bestlen ; j++)

-			used[besttris[j]] = 1;

-

-		if (besttype == 1)

-			commands[numcommands++] = (bestlen+2);

-		else

-			commands[numcommands++] = -(bestlen+2);

-

-		for (j=0 ; j<bestlen+2 ; j++)

-		{

-			// emit a vertex into the reorder buffer

-			k = bestverts[j];

-			vertexorder[numorder++] = k;

-

-			// emit s/t coords into the commands stream

-			s = stverts[k].s;

-			t = stverts[k].t;

-			if (!triangles[besttris[0]].facesfront && stverts[k].onseam)

-				s += pheader->skinwidth / 2;	// on back side

-			s = (s + 0.5) / pheader->skinwidth;

-			t = (t + 0.5) / pheader->skinheight;

-

-			*(float *)&commands[numcommands++] = s;

-			*(float *)&commands[numcommands++] = t;

-		}

-	}

-

-	commands[numcommands++] = 0;		// end of list marker

-

-	Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands);

-

-	allverts += numorder;

-	alltris += pheader->numtris;

-}

-

-

-/*

-================

-GL_MakeAliasModelDisplayLists

-================

-*/

-void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr)

-{

-	int		i, j;

-	maliasgroup_t	*paliasgroup;

-	int			*cmds;

-	trivertx_t	*verts;

-	char	cache[MAX_QPATH], fullpath[MAX_OSPATH], *c;

-	FILE	*f;

-	int		len;

-	byte	*data;

-

-	aliasmodel = m;

-	paliashdr = hdr;	// (aliashdr_t *)Mod_Extradata (m);

-

-	//

-	// look for a cached version

-	//

-	strcpy (cache, "glquake/");

-	COM_StripExtension (m->name+strlen("progs/"), cache+strlen("glquake/"));

-	strcat (cache, ".ms2");

-

-	COM_FOpenFile (cache, &f);	

-	if (f)

-	{

-		fread (&numcommands, 4, 1, f);

-		fread (&numorder, 4, 1, f);

-		fread (&commands, numcommands * sizeof(commands[0]), 1, f);

-		fread (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f);

-		fclose (f);

-	}

-	else

-	{

-		//

-		// build it from scratch

-		//

-		Con_Printf ("meshing %s...\n",m->name);

-

-		BuildTris ();		// trifans or lists

-

-		//

-		// save out the cached version

-		//

-		sprintf (fullpath, "%s/%s", com_gamedir, cache);

-		f = fopen (fullpath, "wb");

-		if (f)

-		{

-			fwrite (&numcommands, 4, 1, f);

-			fwrite (&numorder, 4, 1, f);

-			fwrite (&commands, numcommands * sizeof(commands[0]), 1, f);

-			fwrite (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f);

-			fclose (f);

-		}

-	}

-

-

-	// save the data out

-

-	paliashdr->poseverts = numorder;

-

-	cmds = Hunk_Alloc (numcommands * 4);

-	paliashdr->commands = (byte *)cmds - (byte *)paliashdr;

-	memcpy (cmds, commands, numcommands * 4);

-

-	verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts 

-		* sizeof(trivertx_t) );

-	paliashdr->posedata = (byte *)verts - (byte *)paliashdr;

-	for (i=0 ; i<paliashdr->numposes ; i++)

-		for (j=0 ; j<numorder ; j++)

-			*verts++ = poseverts[i][vertexorder[j]];

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// gl_mesh.c: triangle model functions
+
+#include "quakedef.h"
+
+/*
+=================================================================
+
+ALIAS MODEL DISPLAY LIST GENERATION
+
+=================================================================
+*/
+
+model_t		*aliasmodel;
+aliashdr_t	*paliashdr;
+
+qboolean	used[8192];
+
+// the command list holds counts and s/t values that are valid for
+// every frame
+int		commands[8192];
+int		numcommands;
+
+// all frames will have their vertexes rearranged and expanded
+// so they are in the order expected by the command list
+int		vertexorder[8192];
+int		numorder;
+
+int		allverts, alltris;
+
+int		stripverts[128];
+int		striptris[128];
+int		stripcount;
+
+/*
+================
+StripLength
+================
+*/
+int	StripLength (int starttri, int startv)
+{
+	int			m1, m2;
+	int			j;
+	mtriangle_t	*last, *check;
+	int			k;
+
+	used[starttri] = 2;
+
+	last = &triangles[starttri];
+
+	stripverts[0] = last->vertindex[(startv)%3];
+	stripverts[1] = last->vertindex[(startv+1)%3];
+	stripverts[2] = last->vertindex[(startv+2)%3];
+
+	striptris[0] = starttri;
+	stripcount = 1;
+
+	m1 = last->vertindex[(startv+2)%3];
+	m2 = last->vertindex[(startv+1)%3];
+
+	// look for a matching triangle
+nexttri:
+	for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)
+	{
+		if (check->facesfront != last->facesfront)
+			continue;
+		for (k=0 ; k<3 ; k++)
+		{
+			if (check->vertindex[k] != m1)
+				continue;
+			if (check->vertindex[ (k+1)%3 ] != m2)
+				continue;
+
+			// this is the next part of the fan
+
+			// if we can't use this triangle, this tristrip is done
+			if (used[j])
+				goto done;
+
+			// the new edge
+			if (stripcount & 1)
+				m2 = check->vertindex[ (k+2)%3 ];
+			else
+				m1 = check->vertindex[ (k+2)%3 ];
+
+			stripverts[stripcount+2] = check->vertindex[ (k+2)%3 ];
+			striptris[stripcount] = j;
+			stripcount++;
+
+			used[j] = 2;
+			goto nexttri;
+		}
+	}
+done:
+
+	// clear the temp used flags
+	for (j=starttri+1 ; j<pheader->numtris ; j++)
+		if (used[j] == 2)
+			used[j] = 0;
+
+	return stripcount;
+}
+
+/*
+===========
+FanLength
+===========
+*/
+int	FanLength (int starttri, int startv)
+{
+	int		m1, m2;
+	int		j;
+	mtriangle_t	*last, *check;
+	int		k;
+
+	used[starttri] = 2;
+
+	last = &triangles[starttri];
+
+	stripverts[0] = last->vertindex[(startv)%3];
+	stripverts[1] = last->vertindex[(startv+1)%3];
+	stripverts[2] = last->vertindex[(startv+2)%3];
+
+	striptris[0] = starttri;
+	stripcount = 1;
+
+	m1 = last->vertindex[(startv+0)%3];
+	m2 = last->vertindex[(startv+2)%3];
+
+
+	// look for a matching triangle
+nexttri:
+	for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)
+	{
+		if (check->facesfront != last->facesfront)
+			continue;
+		for (k=0 ; k<3 ; k++)
+		{
+			if (check->vertindex[k] != m1)
+				continue;
+			if (check->vertindex[ (k+1)%3 ] != m2)
+				continue;
+
+			// this is the next part of the fan
+
+			// if we can't use this triangle, this tristrip is done
+			if (used[j])
+				goto done;
+
+			// the new edge
+			m2 = check->vertindex[ (k+2)%3 ];
+
+			stripverts[stripcount+2] = m2;
+			striptris[stripcount] = j;
+			stripcount++;
+
+			used[j] = 2;
+			goto nexttri;
+		}
+	}
+done:
+
+	// clear the temp used flags
+	for (j=starttri+1 ; j<pheader->numtris ; j++)
+		if (used[j] == 2)
+			used[j] = 0;
+
+	return stripcount;
+}
+
+
+/*
+================
+BuildTris
+
+Generate a list of trifans or strips
+for the model, which holds for all frames
+================
+*/
+void BuildTris (void)
+{
+	int		i, j, k;
+	int		startv;
+	mtriangle_t	*last, *check;
+	int		m1, m2;
+	int		striplength;
+	trivertx_t	*v;
+	mtriangle_t *tv;
+	float	s, t;
+	int		index;
+	int		len, bestlen, besttype;
+	int		bestverts[1024];
+	int		besttris[1024];
+	int		type;
+
+	union {
+	    float f;
+	    int i;
+	} temp;
+	//
+	// build tristrips
+	//
+	numorder = 0;
+	numcommands = 0;
+	memset (used, 0, sizeof(used));
+	for (i=0 ; i<pheader->numtris ; i++)
+	{
+		// pick an unused triangle and start the trifan
+		if (used[i])
+			continue;
+
+		bestlen = 0;
+		besttype = 0;
+		for (type = 0 ; type < 2 ; type++)
+//	type = 1;
+		{
+			for (startv =0 ; startv < 3 ; startv++)
+			{
+				if (type == 1)
+					len = StripLength (i, startv);
+				else
+					len = FanLength (i, startv);
+				if (len > bestlen)
+				{
+					besttype = type;
+					bestlen = len;
+					for (j=0 ; j<bestlen+2 ; j++)
+						bestverts[j] = stripverts[j];
+					for (j=0 ; j<bestlen ; j++)
+						besttris[j] = striptris[j];
+				}
+			}
+		}
+
+		// mark the tris on the best strip as used
+		for (j=0 ; j<bestlen ; j++)
+			used[besttris[j]] = 1;
+
+		if (besttype == 1)
+			commands[numcommands++] = (bestlen+2);
+		else
+			commands[numcommands++] = -(bestlen+2);
+
+		for (j=0 ; j<bestlen+2 ; j++)
+		{
+			// emit a vertex into the reorder buffer
+			k = bestverts[j];
+			vertexorder[numorder++] = k;
+
+			// emit s/t coords into the commands stream
+			s = stverts[k].s;
+			t = stverts[k].t;
+			if (!triangles[besttris[0]].facesfront && stverts[k].onseam)
+				s += pheader->skinwidth / 2;	// on back side
+			s = (s + 0.5) / pheader->skinwidth;
+			t = (t + 0.5) / pheader->skinheight;
+
+			temp.f = s;
+			commands[numcommands++] = temp.i;
+			temp.f = t;
+			commands[numcommands++] = temp.i;
+		}
+	}
+
+	commands[numcommands++] = 0;		// end of list marker
+
+	Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands);
+
+	allverts += numorder;
+	alltris += pheader->numtris;
+}
+
+
+/*
+================
+GL_MakeAliasModelDisplayLists
+================
+*/
+void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr)
+{
+	int		i, j;
+	maliasgroup_t	*paliasgroup;
+	int			*cmds;
+	trivertx_t	*verts;
+	char	cache[MAX_QPATH], fullpath[MAX_OSPATH], *c;
+	FILE	*f;
+	int		len;
+	byte	*data;
+
+	aliasmodel = m;
+	paliashdr = hdr;	// (aliashdr_t *)Mod_Extradata (m);
+
+	//
+	// look for a cached version
+	//
+	strcpy (cache, "glquake/");
+	COM_StripExtension (m->name+strlen("progs/"), cache+strlen("glquake/"));
+	strcat (cache, ".ms2");
+
+	COM_FOpenFile (cache, &f);	
+	if (f)
+	{
+		fread (&numcommands, 4, 1, f);
+		fread (&numorder, 4, 1, f);
+		fread (&commands, numcommands * sizeof(commands[0]), 1, f);
+		fread (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f);
+		fclose (f);
+	}
+	else
+	{
+		//
+		// build it from scratch
+		//
+		Con_Printf ("meshing %s...\n",m->name);
+
+		BuildTris ();		// trifans or lists
+
+		//
+		// save out the cached version
+		//
+		sprintf (fullpath, "%s/%s", com_gamedir, cache);
+		f = fopen (fullpath, "wb");
+		if (f)
+		{
+			fwrite (&numcommands, 4, 1, f);
+			fwrite (&numorder, 4, 1, f);
+			fwrite (&commands, numcommands * sizeof(commands[0]), 1, f);
+			fwrite (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f);
+			fclose (f);
+		}
+	}
+
+
+	// save the data out
+
+	paliashdr->poseverts = numorder;
+
+	cmds = (int*) Hunk_Alloc (numcommands * 4);
+	paliashdr->commands = (byte *)cmds - (byte *)paliashdr;
+	memcpy (cmds, commands, numcommands * 4);
+
+	verts = (trivertx_t*)  Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts 
+		* sizeof(trivertx_t) );
+	paliashdr->posedata = (byte *)verts - (byte *)paliashdr;
+	for (i=0 ; i<paliashdr->numposes ; i++)
+		for (j=0 ; j<numorder ; j++)
+			*verts++ = poseverts[i][vertexorder[j]];
+}
+
diff --git a/quake/src/WinQuake/gl_model.c b/quake/src/WinQuake/gl_model.cpp
old mode 100644
new mode 100755
similarity index 92%
rename from quake/src/WinQuake/gl_model.c
rename to quake/src/WinQuake/gl_model.cpp
index 5449094..72649bb
--- a/quake/src/WinQuake/gl_model.c
+++ b/quake/src/WinQuake/gl_model.cpp
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // models.c -- model loading and caching
 
 // models are the only shared resource between a client and server running
@@ -38,7 +38,7 @@
 model_t	mod_known[MAX_MOD_KNOWN];
 int		mod_numknown;
 
-cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", true};
+cvar_t gl_subdivide_size = CVAR3("gl_subdivide_size", "128", true);
 
 /*
 ===============
@@ -181,7 +181,7 @@
 
 ==================
 */
-model_t *Mod_FindName (char *name)
+model_t *Mod_FindName (const char *name)
 {
 	int		i;
 	model_t	*mod;
@@ -214,7 +214,7 @@
 
 ==================
 */
-void Mod_TouchModel (char *name)
+void Mod_TouchModel (const char *name)
 {
 	model_t	*mod;
 	
@@ -274,7 +274,7 @@
 //
 // allocate a new model
 //
-	COM_FileBase (mod->name, loadname);
+	COM_FileBase (mod->name, loadname, sizeof(loadname));
 	
 	loadmodel = mod;
 
@@ -310,7 +310,7 @@
 Loads in a model for the given name
 ==================
 */
-model_t *Mod_ForName (char *name, qboolean crash)
+model_t *Mod_ForName (const char *name, qboolean crash)
 {
 	model_t	*mod;
 	
@@ -355,7 +355,7 @@
 	m->nummiptex = LittleLong (m->nummiptex);
 	
 	loadmodel->numtextures = m->nummiptex;
-	loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);
+	loadmodel->textures = (texture_t**) Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);
 
 	for (i=0 ; i<m->nummiptex ; i++)
 	{
@@ -371,7 +371,7 @@
 		if ( (mt->width & 15) || (mt->height & 15) )
 			Sys_Error ("Texture %s is not 16 aligned", mt->name);
 		pixels = mt->width*mt->height/64*85;
-		tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
+		tx = (texture_t*) Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
 		loadmodel->textures[i] = tx;
 
 		memcpy (tx->name, mt->name, sizeof(tx->name));
@@ -499,7 +499,7 @@
 		loadmodel->lightdata = NULL;
 		return;
 	}
-	loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);	
+	loadmodel->lightdata = (byte*) Hunk_AllocName ( l->filelen, loadname);	
 	memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
 }
 
@@ -516,7 +516,7 @@
 		loadmodel->visdata = NULL;
 		return;
 	}
-	loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname);	
+	loadmodel->visdata = (byte*) Hunk_AllocName ( l->filelen, loadname);	
 	memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
 }
 
@@ -533,7 +533,7 @@
 		loadmodel->entities = NULL;
 		return;
 	}
-	loadmodel->entities = Hunk_AllocName ( l->filelen, loadname);	
+	loadmodel->entities = (char*) Hunk_AllocName ( l->filelen, loadname);	
 	memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
 }
 
@@ -549,11 +549,11 @@
 	mvertex_t	*out;
 	int			i, count;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (dvertex_t*) (void *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (mvertex_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->vertexes = out;
 	loadmodel->numvertexes = count;
@@ -577,11 +577,11 @@
 	dmodel_t	*out;
 	int			i, j, count;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (dmodel_t*) (void *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out =(dmodel_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->submodels = out;
 	loadmodel->numsubmodels = count;
@@ -613,11 +613,11 @@
 	medge_t *out;
 	int 	i, count;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (dedge_t *) (mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);	
+	out = (medge_t*) Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);	
 
 	loadmodel->edges = out;
 	loadmodel->numedges = count;
@@ -642,11 +642,11 @@
 	int		miptex;
 	float	len1, len2;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (texinfo_t *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (mtexinfo_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->texinfo = out;
 	loadmodel->numtexinfo = count;
@@ -738,8 +738,8 @@
 
 	for (i=0 ; i<2 ; i++)
 	{	
-		bmins[i] = floor(mins[i]/16);
-		bmaxs[i] = ceil(maxs[i]/16);
+		bmins[i] = (int) floorf(mins[i]/16);
+		bmaxs[i] = (int) ceilf(maxs[i]/16);
 
 		s->texturemins[i] = bmins[i] * 16;
 		s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
@@ -761,11 +761,11 @@
 	int			i, count, surfnum;
 	int			planenum, side;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (dface_t *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (msurface_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->surfaces = out;
 	loadmodel->numsurfaces = count;
@@ -849,11 +849,11 @@
 	dnode_t		*in;
 	mnode_t 	*out;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (dnode_t *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (mnode_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->nodes = out;
 	loadmodel->numnodes = count;
@@ -896,11 +896,11 @@
 	mleaf_t 	*out;
 	int			i, j, count, p;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (dleaf_t *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (mleaf_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->leafs = out;
 	loadmodel->numleafs = count;
@@ -950,11 +950,11 @@
 	int			i, count;
 	hull_t		*hull;
 
-	in = (void *)(mod_base + l->fileofs);
+	in = (dclipnode_t *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (dclipnode_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->clipnodes = out;
 	loadmodel->numclipnodes = count;
@@ -1009,7 +1009,7 @@
 	
 	in = loadmodel->nodes;
 	count = loadmodel->numnodes;
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (dclipnode_t*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	hull->clipnodes = out;
 	hull->firstclipnode = 0;
@@ -1041,11 +1041,11 @@
 	short		*in;
 	msurface_t **out;
 	
-	in = (void *)(mod_base + l->fileofs);
+	in = (short *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (msurface_t **) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->marksurfaces = out;
 	loadmodel->nummarksurfaces = count;
@@ -1069,11 +1069,11 @@
 	int		i, count;
 	int		*in, *out;
 	
-	in = (void *)(mod_base + l->fileofs);
+	in = (int *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+	out = (int*) Hunk_AllocName ( count*sizeof(*out), loadname);	
 
 	loadmodel->surfedges = out;
 	loadmodel->numsurfedges = count;
@@ -1096,11 +1096,11 @@
 	int			count;
 	int			bits;
 	
-	in = (void *)(mod_base + l->fileofs);
+	in = (dplane_t *)(mod_base + l->fileofs);
 	if (l->filelen % sizeof(*in))
 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
 	count = l->filelen / sizeof(*in);
-	out = Hunk_AllocName ( count*2*sizeof(*out), loadname);	
+	out = (mplane_t*) Hunk_AllocName ( count*2*sizeof(*out), loadname);	
 	
 	loadmodel->planes = out;
 	loadmodel->numplanes = count;
@@ -1161,7 +1161,7 @@
 // swap all the lumps
 	mod_base = (byte *)header;
 
-	for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
+	for (i=0 ; i< (int) (sizeof(dheader_t)/4) ; i++)
 		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
 
 // load into heap
@@ -1434,7 +1434,7 @@
 
 			// save 8 bit texels for the player model to remap
 	//		if (!strcmp(loadmodel->name,"progs/player.mdl")) {
-				texels = Hunk_AllocName(s, loadname);
+				texels = (byte*) Hunk_AllocName(s, loadname);
 				pheader->texels[i] = texels - (byte *)pheader;
 				memcpy (texels, (byte *)(pskintype + 1), s);
 	//		}
@@ -1453,13 +1453,13 @@
 			groupskins = LittleLong (pinskingroup->numskins);
 			pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
 
-			pskintype = (void *)(pinskinintervals + groupskins);
+			pskintype = (daliasskintype_t *)(pinskinintervals + groupskins);
 
 			for (j=0 ; j<groupskins ; j++)
 			{
 					Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
 					if (j == 0) {
-						texels = Hunk_AllocName(s, loadname);
+						texels = (byte*) Hunk_AllocName(s, loadname);
 						pheader->texels[i] = texels - (byte *)pheader;
 						memcpy (texels, (byte *)(pskintype), s);
 					}
@@ -1514,7 +1514,7 @@
 	size = 	sizeof (aliashdr_t) 
 			+ (LittleLong (pinmodel->numframes) - 1) *
 			sizeof (pheader->frames[0]);
-	pheader = Hunk_AllocName (size, loadname);
+	pheader = (aliashdr_t*) Hunk_AllocName (size, loadname);
 	
 	mod->flags = LittleLong (pinmodel->flags);
 
@@ -1549,7 +1549,7 @@
 		Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
 
 	pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
-	mod->synctype = LittleLong (pinmodel->synctype);
+	mod->synctype = (synctype_t) LittleLong (pinmodel->synctype);
 	mod->numframes = pheader->numframes;
 
 	for (i=0 ; i<3 ; i++)
@@ -1564,7 +1564,7 @@
 // load the skins
 //
 	pskintype = (daliasskintype_t *)&pinmodel[1];
-	pskintype = Mod_LoadAllSkins (pheader->numskins, pskintype);
+	pskintype = (daliasskintype_t*) Mod_LoadAllSkins (pheader->numskins, pskintype);
 
 //
 // load base s and t vertices
@@ -1604,7 +1604,7 @@
 	{
 		aliasframetype_t	frametype;
 
-		frametype = LittleLong (pframetype->type);
+		frametype = (aliasframetype_t) LittleLong (pframetype->type);
 
 		if (frametype == ALIAS_SINGLE)
 		{
@@ -1667,7 +1667,7 @@
 	height = LittleLong (pinframe->height);
 	size = width * height;
 
-	pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t),loadname);
+	pspriteframe = (mspriteframe_t*) Hunk_AllocName (sizeof (mspriteframe_t),loadname);
 
 	Q_memset (pspriteframe, 0, sizeof (mspriteframe_t));
 
@@ -1708,7 +1708,7 @@
 
 	numframes = LittleLong (pingroup->numframes);
 
-	pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +
+	pspritegroup = (mspritegroup_t*) Hunk_AllocName (sizeof (mspritegroup_t) +
 				(numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
 
 	pspritegroup->numframes = numframes;
@@ -1717,7 +1717,7 @@
 
 	pin_intervals = (dspriteinterval_t *)(pingroup + 1);
 
-	poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
+	poutintervals = (float*) Hunk_AllocName (numframes * sizeof (float), loadname);
 
 	pspritegroup->intervals = poutintervals;
 
@@ -1768,7 +1768,7 @@
 
 	size = sizeof (msprite_t) +	(numframes - 1) * sizeof (psprite->frames);
 
-	psprite = Hunk_AllocName (size, loadname);
+	psprite = (msprite_t*) Hunk_AllocName (size, loadname);
 
 	mod->cache.data = psprite;
 
@@ -1776,7 +1776,7 @@
 	psprite->maxwidth = LittleLong (pin->width);
 	psprite->maxheight = LittleLong (pin->height);
 	psprite->beamlength = LittleFloat (pin->beamlength);
-	mod->synctype = LittleLong (pin->synctype);
+	mod->synctype = (synctype_t) LittleLong (pin->synctype);
 	psprite->numframes = numframes;
 
 	mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;
@@ -1798,7 +1798,7 @@
 	{
 		spriteframetype_t	frametype;
 
-		frametype = LittleLong (pframetype->type);
+		frametype = (spriteframetype_t) LittleLong (pframetype->type);
 		psprite->frames[i].type = frametype;
 
 		if (frametype == SPR_SINGLE)
diff --git a/quake/src/WinQuake/gl_model.h b/quake/src/WinQuake/gl_model.h
index 64403b6..5f85bb4 100644
--- a/quake/src/WinQuake/gl_model.h
+++ b/quake/src/WinQuake/gl_model.h
@@ -1,430 +1,430 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-#ifndef __MODEL__

-#define __MODEL__

-

-#include "modelgen.h"

-#include "spritegn.h"

-

-/*

-

-d*_t structures are on-disk representations

-m*_t structures are in-memory

-

-*/

-

-// entity effects

-

-#define	EF_BRIGHTFIELD			1

-#define	EF_MUZZLEFLASH 			2

-#define	EF_BRIGHTLIGHT 			4

-#define	EF_DIMLIGHT 			8

-

-

-/*

-==============================================================================

-

-BRUSH MODELS

-

-==============================================================================

-*/

-

-

-//

-// in memory representation

-//

-// !!! if this is changed, it must be changed in asm_draw.h too !!!

-typedef struct

-{

-	vec3_t		position;

-} mvertex_t;

-

-#define	SIDE_FRONT	0

-#define	SIDE_BACK	1

-#define	SIDE_ON		2

-

-

-// plane_t structure

-// !!! if this is changed, it must be changed in asm_i386.h too !!!

-typedef struct mplane_s

-{

-	vec3_t	normal;

-	float	dist;

-	byte	type;			// for texture axis selection and fast side tests

-	byte	signbits;		// signx + signy<<1 + signz<<1

-	byte	pad[2];

-} mplane_t;

-

-typedef struct texture_s

-{

-	char		name[16];

-	unsigned	width, height;

-	int			gl_texturenum;

-	struct msurface_s	*texturechain;	// for gl_texsort drawing

-	int			anim_total;				// total tenths in sequence ( 0 = no)

-	int			anim_min, anim_max;		// time for this frame min <=time< max

-	struct texture_s *anim_next;		// in the animation sequence

-	struct texture_s *alternate_anims;	// bmodels in frmae 1 use these

-	unsigned	offsets[MIPLEVELS];		// four mip maps stored

-} texture_t;

-

-

-#define	SURF_PLANEBACK		2

-#define	SURF_DRAWSKY		4

-#define SURF_DRAWSPRITE		8

-#define SURF_DRAWTURB		0x10

-#define SURF_DRAWTILED		0x20

-#define SURF_DRAWBACKGROUND	0x40

-#define SURF_UNDERWATER		0x80

-

-// !!! if this is changed, it must be changed in asm_draw.h too !!!

-typedef struct

-{

-	unsigned short	v[2];

-	unsigned int	cachededgeoffset;

-} medge_t;

-

-typedef struct

-{

-	float		vecs[2][4];

-	float		mipadjust;

-	texture_t	*texture;

-	int			flags;

-} mtexinfo_t;

-

-#define	VERTEXSIZE	7

-

-typedef struct glpoly_s

-{

-	struct	glpoly_s	*next;

-	struct	glpoly_s	*chain;

-	int		numverts;

-	int		flags;			// for SURF_UNDERWATER

-	float	verts[4][VERTEXSIZE];	// variable sized (xyz s1t1 s2t2)

-} glpoly_t;

-

-typedef struct msurface_s

-{

-	int			visframe;		// should be drawn when node is crossed

-

-	mplane_t	*plane;

-	int			flags;

-

-	int			firstedge;	// look up in model->surfedges[], negative numbers

-	int			numedges;	// are backwards edges

-	

-	short		texturemins[2];

-	short		extents[2];

-

-	int			light_s, light_t;	// gl lightmap coordinates

-

-	glpoly_t	*polys;				// multiple if warped

-	struct	msurface_s	*texturechain;

-

-	mtexinfo_t	*texinfo;

-	

-// lighting info

-	int			dlightframe;

-	int			dlightbits;

-

-	int			lightmaptexturenum;

-	byte		styles[MAXLIGHTMAPS];

-	int			cached_light[MAXLIGHTMAPS];	// values currently used in lightmap

-	qboolean	cached_dlight;				// true if dynamic light in cache

-	byte		*samples;		// [numstyles*surfsize]

-} msurface_t;

-

-typedef struct mnode_s

-{

-// common with leaf

-	int			contents;		// 0, to differentiate from leafs

-	int			visframe;		// node needs to be traversed if current

-	

-	float		minmaxs[6];		// for bounding box culling

-

-	struct mnode_s	*parent;

-

-// node specific

-	mplane_t	*plane;

-	struct mnode_s	*children[2];	

-

-	unsigned short		firstsurface;

-	unsigned short		numsurfaces;

-} mnode_t;

-

-

-

-typedef struct mleaf_s

-{

-// common with node

-	int			contents;		// wil be a negative contents number

-	int			visframe;		// node needs to be traversed if current

-

-	float		minmaxs[6];		// for bounding box culling

-

-	struct mnode_s	*parent;

-

-// leaf specific

-	byte		*compressed_vis;

-	efrag_t		*efrags;

-

-	msurface_t	**firstmarksurface;

-	int			nummarksurfaces;

-	int			key;			// BSP sequence number for leaf's contents

-	byte		ambient_sound_level[NUM_AMBIENTS];

-} mleaf_t;

-

-// !!! if this is changed, it must be changed in asm_i386.h too !!!

-typedef struct

-{

-	dclipnode_t	*clipnodes;

-	mplane_t	*planes;

-	int			firstclipnode;

-	int			lastclipnode;

-	vec3_t		clip_mins;

-	vec3_t		clip_maxs;

-} hull_t;

-

-/*

-==============================================================================

-

-SPRITE MODELS

-

-==============================================================================

-*/

-

-

-// FIXME: shorten these?

-typedef struct mspriteframe_s

-{

-	int		width;

-	int		height;

-	float	up, down, left, right;

-	int		gl_texturenum;

-} mspriteframe_t;

-

-typedef struct

-{

-	int				numframes;

-	float			*intervals;

-	mspriteframe_t	*frames[1];

-} mspritegroup_t;

-

-typedef struct

-{

-	spriteframetype_t	type;

-	mspriteframe_t		*frameptr;

-} mspriteframedesc_t;

-

-typedef struct

-{

-	int					type;

-	int					maxwidth;

-	int					maxheight;

-	int					numframes;

-	float				beamlength;		// remove?

-	void				*cachespot;		// remove?

-	mspriteframedesc_t	frames[1];

-} msprite_t;

-

-

-/*

-==============================================================================

-

-ALIAS MODELS

-

-Alias models are position independent, so the cache manager can move them.

-==============================================================================

-*/

-

-typedef struct

-{

-	int					firstpose;

-	int					numposes;

-	float				interval;

-	trivertx_t			bboxmin;

-	trivertx_t			bboxmax;

-	int					frame;

-	char				name[16];

-} maliasframedesc_t;

-

-typedef struct

-{

-	trivertx_t			bboxmin;

-	trivertx_t			bboxmax;

-	int					frame;

-} maliasgroupframedesc_t;

-

-typedef struct

-{

-	int						numframes;

-	int						intervals;

-	maliasgroupframedesc_t	frames[1];

-} maliasgroup_t;

-

-// !!! if this is changed, it must be changed in asm_draw.h too !!!

-typedef struct mtriangle_s {

-	int					facesfront;

-	int					vertindex[3];

-} mtriangle_t;

-

-

-#define	MAX_SKINS	32

-typedef struct {

-	int			ident;

-	int			version;

-	vec3_t		scale;

-	vec3_t		scale_origin;

-	float		boundingradius;

-	vec3_t		eyeposition;

-	int			numskins;

-	int			skinwidth;

-	int			skinheight;

-	int			numverts;

-	int			numtris;

-	int			numframes;

-	synctype_t	synctype;

-	int			flags;

-	float		size;

-

-	int					numposes;

-	int					poseverts;

-	int					posedata;	// numposes*poseverts trivert_t

-	int					commands;	// gl command list with embedded s/t

-	int					gl_texturenum[MAX_SKINS][4];

-	int					texels[MAX_SKINS];	// only for player skins

-	maliasframedesc_t	frames[1];	// variable sized

-} aliashdr_t;

-

-#define	MAXALIASVERTS	1024

-#define	MAXALIASFRAMES	256

-#define	MAXALIASTRIS	2048

-extern	aliashdr_t	*pheader;

-extern	stvert_t	stverts[MAXALIASVERTS];

-extern	mtriangle_t	triangles[MAXALIASTRIS];

-extern	trivertx_t	*poseverts[MAXALIASFRAMES];

-

-//===================================================================

-

-//

-// Whole model

-//

-

-typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;

-

-#define	EF_ROCKET	1			// leave a trail

-#define	EF_GRENADE	2			// leave a trail

-#define	EF_GIB		4			// leave a trail

-#define	EF_ROTATE	8			// rotate (bonus items)

-#define	EF_TRACER	16			// green split trail

-#define	EF_ZOMGIB	32			// small blood trail

-#define	EF_TRACER2	64			// orange split trail + rotate

-#define	EF_TRACER3	128			// purple trail

-

-typedef struct model_s

-{

-	char		name[MAX_QPATH];

-	qboolean	needload;		// bmodels and sprites don't cache normally

-

-	modtype_t	type;

-	int			numframes;

-	synctype_t	synctype;

-	

-	int			flags;

-

-//

-// volume occupied by the model graphics

-//		

-	vec3_t		mins, maxs;

-	float		radius;

-

-//

-// solid volume for clipping 

-//

-	qboolean	clipbox;

-	vec3_t		clipmins, clipmaxs;

-

-//

-// brush model

-//

-	int			firstmodelsurface, nummodelsurfaces;

-

-	int			numsubmodels;

-	dmodel_t	*submodels;

-

-	int			numplanes;

-	mplane_t	*planes;

-

-	int			numleafs;		// number of visible leafs, not counting 0

-	mleaf_t		*leafs;

-

-	int			numvertexes;

-	mvertex_t	*vertexes;

-

-	int			numedges;

-	medge_t		*edges;

-

-	int			numnodes;

-	mnode_t		*nodes;

-

-	int			numtexinfo;

-	mtexinfo_t	*texinfo;

-

-	int			numsurfaces;

-	msurface_t	*surfaces;

-

-	int			numsurfedges;

-	int			*surfedges;

-

-	int			numclipnodes;

-	dclipnode_t	*clipnodes;

-

-	int			nummarksurfaces;

-	msurface_t	**marksurfaces;

-

-	hull_t		hulls[MAX_MAP_HULLS];

-

-	int			numtextures;

-	texture_t	**textures;

-

-	byte		*visdata;

-	byte		*lightdata;

-	char		*entities;

-

-//

-// additional model data

-//

-	cache_user_t	cache;		// only access through Mod_Extradata

-

-} model_t;

-

-//============================================================================

-

-void	Mod_Init (void);

-void	Mod_ClearAll (void);

-model_t *Mod_ForName (char *name, qboolean crash);

-void	*Mod_Extradata (model_t *mod);	// handles caching

-void	Mod_TouchModel (char *name);

-

-mleaf_t *Mod_PointInLeaf (float *p, model_t *model);

-byte	*Mod_LeafPVS (mleaf_t *leaf, model_t *model);

-

-#endif	// __MODEL__

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifndef __MODEL__
+#define __MODEL__
+
+#include "modelgen.h"
+#include "spritegn.h"
+
+/*
+
+d*_t structures are on-disk representations
+m*_t structures are in-memory
+
+*/
+
+// entity effects
+
+#define	EF_BRIGHTFIELD			1
+#define	EF_MUZZLEFLASH 			2
+#define	EF_BRIGHTLIGHT 			4
+#define	EF_DIMLIGHT 			8
+
+
+/*
+==============================================================================
+
+BRUSH MODELS
+
+==============================================================================
+*/
+
+
+//
+// in memory representation
+//
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct
+{
+	vec3_t		position;
+} mvertex_t;
+
+#define	SIDE_FRONT	0
+#define	SIDE_BACK	1
+#define	SIDE_ON		2
+
+
+// plane_t structure
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct mplane_s
+{
+	vec3_t	normal;
+	float	dist;
+	byte	type;			// for texture axis selection and fast side tests
+	byte	signbits;		// signx + signy<<1 + signz<<1
+	byte	pad[2];
+} mplane_t;
+
+typedef struct texture_s
+{
+	char		name[16];
+	unsigned	width, height;
+	int			gl_texturenum;
+	struct msurface_s	*texturechain;	// for gl_texsort drawing
+	int			anim_total;				// total tenths in sequence ( 0 = no)
+	int			anim_min, anim_max;		// time for this frame min <=time< max
+	struct texture_s *anim_next;		// in the animation sequence
+	struct texture_s *alternate_anims;	// bmodels in frmae 1 use these
+	unsigned	offsets[MIPLEVELS];		// four mip maps stored
+} texture_t;
+
+
+#define	SURF_PLANEBACK		2
+#define	SURF_DRAWSKY		4
+#define SURF_DRAWSPRITE		8
+#define SURF_DRAWTURB		0x10
+#define SURF_DRAWTILED		0x20
+#define SURF_DRAWBACKGROUND	0x40
+#define SURF_UNDERWATER		0x80
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct
+{
+	unsigned short	v[2];
+	unsigned int	cachededgeoffset;
+} medge_t;
+
+typedef struct
+{
+	float		vecs[2][4];
+	float		mipadjust;
+	texture_t	*texture;
+	int			flags;
+} mtexinfo_t;
+
+#define	VERTEXSIZE	7
+
+typedef struct glpoly_s
+{
+	struct	glpoly_s	*next;
+	struct	glpoly_s	*chain;
+	int		numverts;
+	int		flags;			// for SURF_UNDERWATER
+	float	verts[4][VERTEXSIZE];	// variable sized (xyz s1t1 s2t2)
+} glpoly_t;
+
+typedef struct msurface_s
+{
+	int			visframe;		// should be drawn when node is crossed
+
+	mplane_t	*plane;
+	int			flags;
+
+	int			firstedge;	// look up in model->surfedges[], negative numbers
+	int			numedges;	// are backwards edges
+	
+	short		texturemins[2];
+	short		extents[2];
+
+	int			light_s, light_t;	// gl lightmap coordinates
+
+	glpoly_t	*polys;				// multiple if warped
+	struct	msurface_s	*texturechain;
+
+	mtexinfo_t	*texinfo;
+	
+// lighting info
+	int			dlightframe;
+	int			dlightbits;
+
+	int			lightmaptexturenum;
+	byte		styles[MAXLIGHTMAPS];
+	int			cached_light[MAXLIGHTMAPS];	// values currently used in lightmap
+	qboolean	cached_dlight;				// true if dynamic light in cache
+	byte		*samples;		// [numstyles*surfsize]
+} msurface_t;
+
+typedef struct mnode_s
+{
+// common with leaf
+	int			contents;		// 0, to differentiate from leafs
+	int			visframe;		// node needs to be traversed if current
+	
+	float		minmaxs[6];		// for bounding box culling
+
+	struct mnode_s	*parent;
+
+// node specific
+	mplane_t	*plane;
+	struct mnode_s	*children[2];	
+
+	unsigned short		firstsurface;
+	unsigned short		numsurfaces;
+} mnode_t;
+
+
+
+typedef struct mleaf_s
+{
+// common with node
+	int			contents;		// wil be a negative contents number
+	int			visframe;		// node needs to be traversed if current
+
+	float		minmaxs[6];		// for bounding box culling
+
+	struct mnode_s	*parent;
+
+// leaf specific
+	byte		*compressed_vis;
+	efrag_t		*efrags;
+
+	msurface_t	**firstmarksurface;
+	int			nummarksurfaces;
+	int			key;			// BSP sequence number for leaf's contents
+	byte		ambient_sound_level[NUM_AMBIENTS];
+} mleaf_t;
+
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct
+{
+	dclipnode_t	*clipnodes;
+	mplane_t	*planes;
+	int			firstclipnode;
+	int			lastclipnode;
+	vec3_t		clip_mins;
+	vec3_t		clip_maxs;
+} hull_t;
+
+/*
+==============================================================================
+
+SPRITE MODELS
+
+==============================================================================
+*/
+
+
+// FIXME: shorten these?
+typedef struct mspriteframe_s
+{
+	int		width;
+	int		height;
+	float	up, down, left, right;
+	int		gl_texturenum;
+} mspriteframe_t;
+
+typedef struct
+{
+	int				numframes;
+	float			*intervals;
+	mspriteframe_t	*frames[1];
+} mspritegroup_t;
+
+typedef struct
+{
+	spriteframetype_t	type;
+	mspriteframe_t		*frameptr;
+} mspriteframedesc_t;
+
+typedef struct
+{
+	int					type;
+	int					maxwidth;
+	int					maxheight;
+	int					numframes;
+	float				beamlength;		// remove?
+	void				*cachespot;		// remove?
+	mspriteframedesc_t	frames[1];
+} msprite_t;
+
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+Alias models are position independent, so the cache manager can move them.
+==============================================================================
+*/
+
+typedef struct
+{
+	int					firstpose;
+	int					numposes;
+	float				interval;
+	trivertx_t			bboxmin;
+	trivertx_t			bboxmax;
+	int					frame;
+	char				name[16];
+} maliasframedesc_t;
+
+typedef struct
+{
+	trivertx_t			bboxmin;
+	trivertx_t			bboxmax;
+	int					frame;
+} maliasgroupframedesc_t;
+
+typedef struct
+{
+	int						numframes;
+	int						intervals;
+	maliasgroupframedesc_t	frames[1];
+} maliasgroup_t;
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct mtriangle_s {
+	int					facesfront;
+	int					vertindex[3];
+} mtriangle_t;
+
+
+#define	MAX_SKINS	32
+typedef struct {
+	int			ident;
+	int			version;
+	vec3_t		scale;
+	vec3_t		scale_origin;
+	float		boundingradius;
+	vec3_t		eyeposition;
+	int			numskins;
+	int			skinwidth;
+	int			skinheight;
+	int			numverts;
+	int			numtris;
+	int			numframes;
+	synctype_t	synctype;
+	int			flags;
+	float		size;
+
+	int					numposes;
+	int					poseverts;
+	int					posedata;	// numposes*poseverts trivert_t
+	int					commands;	// gl command list with embedded s/t
+	int					gl_texturenum[MAX_SKINS][4];
+	int					texels[MAX_SKINS];	// only for player skins
+	maliasframedesc_t	frames[1];	// variable sized
+} aliashdr_t;
+
+#define	MAXALIASVERTS	1024
+#define	MAXALIASFRAMES	256
+#define	MAXALIASTRIS	2048
+extern	aliashdr_t	*pheader;
+extern	stvert_t	stverts[MAXALIASVERTS];
+extern	mtriangle_t	triangles[MAXALIASTRIS];
+extern	trivertx_t	*poseverts[MAXALIASFRAMES];
+
+//===================================================================
+
+//
+// Whole model
+//
+
+typedef enum {mod_brush, mod_sprite, mod_alias, modtype_t_max = 1 << 30} modtype_t;
+
+#define	EF_ROCKET	1			// leave a trail
+#define	EF_GRENADE	2			// leave a trail
+#define	EF_GIB		4			// leave a trail
+#define	EF_ROTATE	8			// rotate (bonus items)
+#define	EF_TRACER	16			// green split trail
+#define	EF_ZOMGIB	32			// small blood trail
+#define	EF_TRACER2	64			// orange split trail + rotate
+#define	EF_TRACER3	128			// purple trail
+
+typedef struct model_s
+{
+	char		name[MAX_QPATH];
+	qboolean	needload;		// bmodels and sprites don't cache normally
+
+	modtype_t	type;
+	int			numframes;
+	synctype_t	synctype;
+	
+	int			flags;
+
+//
+// volume occupied by the model graphics
+//		
+	vec3_t		mins, maxs;
+	float		radius;
+
+//
+// solid volume for clipping 
+//
+	qboolean	clipbox;
+	vec3_t		clipmins, clipmaxs;
+
+//
+// brush model
+//
+	int			firstmodelsurface, nummodelsurfaces;
+
+	int			numsubmodels;
+	dmodel_t	*submodels;
+
+	int			numplanes;
+	mplane_t	*planes;
+
+	int			numleafs;		// number of visible leafs, not counting 0
+	mleaf_t		*leafs;
+
+	int			numvertexes;
+	mvertex_t	*vertexes;
+
+	int			numedges;
+	medge_t		*edges;
+
+	int			numnodes;
+	mnode_t		*nodes;
+
+	int			numtexinfo;
+	mtexinfo_t	*texinfo;
+
+	int			numsurfaces;
+	msurface_t	*surfaces;
+
+	int			numsurfedges;
+	int			*surfedges;
+
+	int			numclipnodes;
+	dclipnode_t	*clipnodes;
+
+	int			nummarksurfaces;
+	msurface_t	**marksurfaces;
+
+	hull_t		hulls[MAX_MAP_HULLS];
+
+	int			numtextures;
+	texture_t	**textures;
+
+	byte		*visdata;
+	byte		*lightdata;
+	char		*entities;
+
+//
+// additional model data
+//
+	cache_user_t	cache;		// only access through Mod_Extradata
+
+} model_t;
+
+//============================================================================
+
+void	Mod_Init (void);
+void	Mod_ClearAll (void);
+model_t *Mod_ForName (const char *name, qboolean crash);
+void	*Mod_Extradata (model_t *mod);	// handles caching
+void	Mod_TouchModel (const char *name);
+
+mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
+byte	*Mod_LeafPVS (mleaf_t *leaf, model_t *model);
+
+#endif	// __MODEL__
diff --git a/quake/src/WinQuake/gl_refrag.c b/quake/src/WinQuake/gl_refrag.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/gl_refrag.c
rename to quake/src/WinQuake/gl_refrag.cpp
diff --git a/quake/src/WinQuake/gl_rlight.c b/quake/src/WinQuake/gl_rlight.cpp
old mode 100644
new mode 100755
similarity index 87%
rename from quake/src/WinQuake/gl_rlight.c
rename to quake/src/WinQuake/gl_rlight.cpp
index 6155001..65da688
--- a/quake/src/WinQuake/gl_rlight.c
+++ b/quake/src/WinQuake/gl_rlight.cpp
@@ -17,40 +17,40 @@
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 

 */

-// r_light.c
-
+// r_light.c

+

 #include "quakedef.h"

-
-int	r_dlightframecount;
-
-
-/*
-==================
-R_AnimateLight
-==================
-*/
-void R_AnimateLight (void)
-{
-	int			i,j,k;
-	
-//
-// light animations
-// 'm' is normal light, 'a' is no light, 'z' is double bright
-	i = (int)(cl.time*10);
-	for (j=0 ; j<MAX_LIGHTSTYLES ; j++)
-	{
-		if (!cl_lightstyle[j].length)
-		{
-			d_lightstylevalue[j] = 256;
-			continue;
-		}
-		k = i % cl_lightstyle[j].length;
-		k = cl_lightstyle[j].map[k] - 'a';
-		k = k*22;
-		d_lightstylevalue[j] = k;
-	}	
-}
-
+

+int	r_dlightframecount;

+

+

+/*

+==================

+R_AnimateLight

+==================

+*/

+void R_AnimateLight (void)

+{

+	int			i,j,k;

+	

+//

+// light animations

+// 'm' is normal light, 'a' is no light, 'z' is double bright

+	i = (int)(cl.time*10);

+	for (j=0 ; j<MAX_LIGHTSTYLES ; j++)

+	{

+		if (!cl_lightstyle[j].length)

+		{

+			d_lightstylevalue[j] = 256;

+			continue;

+		}

+		k = i % cl_lightstyle[j].length;

+		k = cl_lightstyle[j].map[k] - 'a';

+		k = k*22;

+		d_lightstylevalue[j] = k;

+	}	

+}

+

 /*

 =============================================================================

 

@@ -88,6 +88,37 @@
 		return;

 	}

 

+#ifdef USE_OPENGLES

+    glEnableClientState(GL_COLOR_ARRAY);

+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

+	glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);

+	glColorPointer(3, GL_FLOAT, 0, gColorBuffer);

+

+	{

+	    float* pPos = gVertexBuffer;

+		float* pColor = gColorBuffer;

+		*pColor++ = 0.2;

+		*pColor++ = 0.1;

+		*pColor++ = 0.0;

+		for (i=0 ; i<3 ; i++)

+			*pPos++ = light->origin[i] - vpn[i]*rad;

+		for (i=16 ; i>=0 ; i--)

+		{

+			*pColor++ = 0.0;

+			*pColor++ = 0.0;

+			*pColor++ = 0.0;

+			a = i/16.0 * M_PI*2;

+			for (j=0 ; j<3 ; j++)

+				*pPos++ = light->origin[j] + vright[j]*cos(a)*rad

+					+ vup[j]*sin(a)*rad;

+		}

+	}

+	glDrawArrays(GL_TRIANGLE_FAN, 0, 18);

+    glDisableClientState(GL_COLOR_ARRAY);

+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

+	glColor3f(0,0,0); // Ensure the color ends up being zero just like the non-OpenGLES code

+	

+#else

 	glBegin (GL_TRIANGLE_FAN);

 	glColor3f (0.2,0.1,0.0);

 	for (i=0 ; i<3 ; i++)

@@ -103,6 +134,7 @@
 		glVertex3fv (v);

 	}

 	glEnd ();

+#endif

 }

 

 /*

@@ -141,214 +173,213 @@
 	glDepthMask (1);

 }

 

-
-/*
-=============================================================================
-
-DYNAMIC LIGHTS
-
-=============================================================================
-*/
-
-/*
-=============
-R_MarkLights
-=============
-*/
-void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
-{
-	mplane_t	*splitplane;
-	float		dist;
-	msurface_t	*surf;
-	int			i;
-	
-	if (node->contents < 0)
-		return;
-
-	splitplane = node->plane;
-	dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
-	
-	if (dist > light->radius)
-	{
-		R_MarkLights (light, bit, node->children[0]);
-		return;
-	}
-	if (dist < -light->radius)
-	{
-		R_MarkLights (light, bit, node->children[1]);
-		return;
-	}
-		
-// mark the polygons
-	surf = cl.worldmodel->surfaces + node->firstsurface;
-	for (i=0 ; i<node->numsurfaces ; i++, surf++)
-	{
-		if (surf->dlightframe != r_dlightframecount)
-		{
-			surf->dlightbits = 0;
-			surf->dlightframe = r_dlightframecount;
-		}
-		surf->dlightbits |= bit;
-	}
-
-	R_MarkLights (light, bit, node->children[0]);
-	R_MarkLights (light, bit, node->children[1]);
-}
-
-
-/*
-=============
-R_PushDlights
-=============
-*/
-void R_PushDlights (void)
-{
-	int		i;
-	dlight_t	*l;
+

+/*

+=============================================================================

+

+DYNAMIC LIGHTS

+

+=============================================================================

+*/

+

+/*

+=============

+R_MarkLights

+=============

+*/

+void R_MarkLights (dlight_t *light, int bit, mnode_t *node)

+{

+	mplane_t	*splitplane;

+	float		dist;

+	msurface_t	*surf;

+	int			i;

+	

+	if (node->contents < 0)

+		return;

+

+	splitplane = node->plane;

+	dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;

+	

+	if (dist > light->radius)

+	{

+		R_MarkLights (light, bit, node->children[0]);

+		return;

+	}

+	if (dist < -light->radius)

+	{

+		R_MarkLights (light, bit, node->children[1]);

+		return;

+	}

+		

+// mark the polygons

+	surf = cl.worldmodel->surfaces + node->firstsurface;

+	for (i=0 ; i<node->numsurfaces ; i++, surf++)

+	{

+		if (surf->dlightframe != r_dlightframecount)

+		{

+			surf->dlightbits = 0;

+			surf->dlightframe = r_dlightframecount;

+		}

+		surf->dlightbits |= bit;

+	}

+

+	R_MarkLights (light, bit, node->children[0]);

+	R_MarkLights (light, bit, node->children[1]);

+}

+

+

+/*

+=============

+R_PushDlights

+=============

+*/

+void R_PushDlights (void)

+{

+	int		i;

+	dlight_t	*l;

 

 	if (gl_flashblend.value)

 		return;

-
-	r_dlightframecount = r_framecount + 1;	// because the count hasn't
-											//  advanced yet for this frame
-	l = cl_dlights;
-
-	for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
-	{
-		if (l->die < cl.time || !l->radius)
-			continue;
-		R_MarkLights ( l, 1<<i, cl.worldmodel->nodes );
-	}
-}
-
-
-/*
-=============================================================================
-
-LIGHT SAMPLING
-
-=============================================================================
-*/
+

+	r_dlightframecount = r_framecount + 1;	// because the count hasn't

+											//  advanced yet for this frame

+	l = cl_dlights;

+

+	for (i=0 ; i<MAX_DLIGHTS ; i++, l++)

+	{

+		if (l->die < cl.time || !l->radius)

+			continue;

+		R_MarkLights ( l, 1<<i, cl.worldmodel->nodes );

+	}

+}

+

+

+/*

+=============================================================================

+

+LIGHT SAMPLING

+

+=============================================================================

+*/

 

 mplane_t		*lightplane;

 vec3_t			lightspot;

-
-int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
-{
-	int			r;
-	float		front, back, frac;
-	int			side;
-	mplane_t	*plane;
-	vec3_t		mid;
-	msurface_t	*surf;
-	int			s, t, ds, dt;
-	int			i;
-	mtexinfo_t	*tex;
-	byte		*lightmap;
-	unsigned	scale;
-	int			maps;
-
-	if (node->contents < 0)
-		return -1;		// didn't hit anything
-	
-// calculate mid point
-
-// FIXME: optimize for axial
-	plane = node->plane;
-	front = DotProduct (start, plane->normal) - plane->dist;
-	back = DotProduct (end, plane->normal) - plane->dist;
-	side = front < 0;
-	
-	if ( (back < 0) == side)
-		return RecursiveLightPoint (node->children[side], start, end);
-	
-	frac = front / (front-back);
-	mid[0] = start[0] + (end[0] - start[0])*frac;
-	mid[1] = start[1] + (end[1] - start[1])*frac;
-	mid[2] = start[2] + (end[2] - start[2])*frac;
-	
-// go down front side	
-	r = RecursiveLightPoint (node->children[side], start, mid);
-	if (r >= 0)
-		return r;		// hit something
-		
-	if ( (back < 0) == side )
-		return -1;		// didn't hit anuthing
-		
-// check for impact on this node
+

+int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)

+{

+	int			r;

+	float		front, back, frac;

+	int			side;

+	mplane_t	*plane;

+	vec3_t		mid;

+	msurface_t	*surf;

+	int			s, t, ds, dt;

+	int			i;

+	mtexinfo_t	*tex;

+	byte		*lightmap;

+	unsigned	scale;

+	int			maps;

+

+	if (node->contents < 0)

+		return -1;		// didn't hit anything

+	

+// calculate mid point

+

+// FIXME: optimize for axial

+	plane = node->plane;

+	front = DotProduct (start, plane->normal) - plane->dist;

+	back = DotProduct (end, plane->normal) - plane->dist;

+	side = front < 0;

+	

+	if ( (back < 0) == side)

+		return RecursiveLightPoint (node->children[side], start, end);

+	

+	frac = front / (front-back);

+	mid[0] = start[0] + (end[0] - start[0])*frac;

+	mid[1] = start[1] + (end[1] - start[1])*frac;

+	mid[2] = start[2] + (end[2] - start[2])*frac;

+	

+// go down front side	

+	r = RecursiveLightPoint (node->children[side], start, mid);

+	if (r >= 0)

+		return r;		// hit something

+		

+	if ( (back < 0) == side )

+		return -1;		// didn't hit anuthing

+		

+// check for impact on this node

 	VectorCopy (mid, lightspot);

 	lightplane = plane;

-
-	surf = cl.worldmodel->surfaces + node->firstsurface;
-	for (i=0 ; i<node->numsurfaces ; i++, surf++)
-	{
-		if (surf->flags & SURF_DRAWTILED)
-			continue;	// no lightmaps
-
-		tex = surf->texinfo;
-		
-		s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
-		t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];;
-
-		if (s < surf->texturemins[0] ||
-		t < surf->texturemins[1])
-			continue;
-		
-		ds = s - surf->texturemins[0];
-		dt = t - surf->texturemins[1];
-		
-		if ( ds > surf->extents[0] || dt > surf->extents[1] )
-			continue;
-
-		if (!surf->samples)
-			return 0;
-
-		ds >>= 4;
-		dt >>= 4;
-
-		lightmap = surf->samples;
-		r = 0;
-		if (lightmap)
-		{
-
-			lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
-
-			for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
-					maps++)
-			{
-				scale = d_lightstylevalue[surf->styles[maps]];
-				r += *lightmap * scale;
-				lightmap += ((surf->extents[0]>>4)+1) *
-						((surf->extents[1]>>4)+1);
-			}
-			
-			r >>= 8;
-		}
-		
-		return r;
-	}
-
-// go down back side
-	return RecursiveLightPoint (node->children[!side], mid, end);
-}
-
-int R_LightPoint (vec3_t p)
-{
-	vec3_t		end;
-	int			r;
-	
-	if (!cl.worldmodel->lightdata)
-		return 255;
-	
-	end[0] = p[0];
-	end[1] = p[1];
-	end[2] = p[2] - 2048;
-	
-	r = RecursiveLightPoint (cl.worldmodel->nodes, p, end);
-	
-	if (r == -1)
-		r = 0;
-
-	return r;
-}
-
+

+	surf = cl.worldmodel->surfaces + node->firstsurface;

+	for (i=0 ; i<node->numsurfaces ; i++, surf++)

+	{

+		if (surf->flags & SURF_DRAWTILED)

+			continue;	// no lightmaps

+

+		tex = surf->texinfo;

+		

+		s = (int) (DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]);

+		t = (int) (DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3]);

+

+		if (s < surf->texturemins[0] ||

+		t < surf->texturemins[1])

+			continue;

+		

+		ds = s - surf->texturemins[0];

+		dt = t - surf->texturemins[1];

+		

+		if ( ds > surf->extents[0] || dt > surf->extents[1] )

+			continue;

+

+		if (!surf->samples)

+			return 0;

+

+		ds >>= 4;

+		dt >>= 4;

+

+		lightmap = surf->samples;

+		r = 0;

+		if (lightmap)

+		{

+

+			lightmap += dt * ((surf->extents[0]>>4)+1) + ds;

+

+			for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;

+					maps++)

+			{

+				scale = d_lightstylevalue[surf->styles[maps]];

+				r += *lightmap * scale;

+				lightmap += ((surf->extents[0]>>4)+1) *

+						((surf->extents[1]>>4)+1);

+			}

+			

+			r >>= 8;

+		}

+		

+		return r;

+	}

+

+// go down back side

+	return RecursiveLightPoint (node->children[!side], mid, end);

+}

+

+int R_LightPoint (vec3_t p)

+{

+	vec3_t		end;

+	int			r;

+	

+	if (!cl.worldmodel->lightdata)

+		return 255;

+	

+	end[0] = p[0];

+	end[1] = p[1];

+	end[2] = p[2] - 2048;

+	

+	r = RecursiveLightPoint (cl.worldmodel->nodes, p, end);

+	

+	if (r == -1)

+		r = 0;

+

+	return r;

+}

diff --git a/quake/src/WinQuake/gl_rmain.c b/quake/src/WinQuake/gl_rmain.cpp
old mode 100644
new mode 100755
similarity index 67%
rename from quake/src/WinQuake/gl_rmain.c
rename to quake/src/WinQuake/gl_rmain.cpp
index b760b71..064deb4
--- a/quake/src/WinQuake/gl_rmain.c
+++ b/quake/src/WinQuake/gl_rmain.cpp
@@ -1,1159 +1,1528 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// r_main.c

-

-#include "quakedef.h"

-

-entity_t	r_worldentity;

-

-qboolean	r_cache_thrash;		// compatability

-

-vec3_t		modelorg, r_entorigin;

-entity_t	*currententity;

-

-int			r_visframecount;	// bumped when going to a new PVS

-int			r_framecount;		// used for dlight push checking

-

-mplane_t	frustum[4];

-

-int			c_brush_polys, c_alias_polys;

-

-qboolean	envmap;				// true during envmap command capture 

-

-int			currenttexture = -1;		// to avoid unnecessary texture sets

-

-int			cnttextures[2] = {-1, -1};     // cached

-

-int			particletexture;	// little dot for particles

-int			playertextures;		// up to 16 color translated skins

-

-int			mirrortexturenum;	// quake texturenum, not gltexturenum

-qboolean	mirror;

-mplane_t	*mirror_plane;

-

-//

-// view origin

-//

-vec3_t	vup;

-vec3_t	vpn;

-vec3_t	vright;

-vec3_t	r_origin;

-

-float	r_world_matrix[16];

-float	r_base_world_matrix[16];

-

-//

-// screen size info

-//

-refdef_t	r_refdef;

-

-mleaf_t		*r_viewleaf, *r_oldviewleaf;

-

-texture_t	*r_notexture_mip;

-

-int		d_lightstylevalue[256];	// 8.8 fraction of base light value

-

-

-void R_MarkLeaves (void);

-

-cvar_t	r_norefresh = {"r_norefresh","0"};

-cvar_t	r_drawentities = {"r_drawentities","1"};

-cvar_t	r_drawviewmodel = {"r_drawviewmodel","1"};

-cvar_t	r_speeds = {"r_speeds","0"};

-cvar_t	r_fullbright = {"r_fullbright","0"};

-cvar_t	r_lightmap = {"r_lightmap","0"};

-cvar_t	r_shadows = {"r_shadows","0"};

-cvar_t	r_mirroralpha = {"r_mirroralpha","1"};

-cvar_t	r_wateralpha = {"r_wateralpha","1"};

-cvar_t	r_dynamic = {"r_dynamic","1"};

-cvar_t	r_novis = {"r_novis","0"};

-

-cvar_t	gl_finish = {"gl_finish","0"};

-cvar_t	gl_clear = {"gl_clear","0"};

-cvar_t	gl_cull = {"gl_cull","1"};

-cvar_t	gl_texsort = {"gl_texsort","1"};

-cvar_t	gl_smoothmodels = {"gl_smoothmodels","1"};

-cvar_t	gl_affinemodels = {"gl_affinemodels","0"};

-cvar_t	gl_polyblend = {"gl_polyblend","1"};

-cvar_t	gl_flashblend = {"gl_flashblend","1"};

-cvar_t	gl_playermip = {"gl_playermip","0"};

-cvar_t	gl_nocolors = {"gl_nocolors","0"};

-cvar_t	gl_keeptjunctions = {"gl_keeptjunctions","0"};

-cvar_t	gl_reporttjunctions = {"gl_reporttjunctions","0"};

-cvar_t	gl_doubleeyes = {"gl_doubleeys", "1"};

-

-extern	cvar_t	gl_ztrick;

-

-/*

-=================

-R_CullBox

-

-Returns true if the box is completely outside the frustom

-=================

-*/

-qboolean R_CullBox (vec3_t mins, vec3_t maxs)

-{

-	int		i;

-

-	for (i=0 ; i<4 ; i++)

-		if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2)

-			return true;

-	return false;

-}

-

-

-void R_RotateForEntity (entity_t *e)

-{

-    glTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);

-

-    glRotatef (e->angles[1],  0, 0, 1);

-    glRotatef (-e->angles[0],  0, 1, 0);

-    glRotatef (e->angles[2],  1, 0, 0);

-}

-

-/*

-=============================================================

-

-  SPRITE MODELS

-

-=============================================================

-*/

-

-/*

-================

-R_GetSpriteFrame

-================

-*/

-mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)

-{

-	msprite_t		*psprite;

-	mspritegroup_t	*pspritegroup;

-	mspriteframe_t	*pspriteframe;

-	int				i, numframes, frame;

-	float			*pintervals, fullinterval, targettime, time;

-

-	psprite = currententity->model->cache.data;

-	frame = currententity->frame;

-

-	if ((frame >= psprite->numframes) || (frame < 0))

-	{

-		Con_Printf ("R_DrawSprite: no such frame %d\n", frame);

-		frame = 0;

-	}

-

-	if (psprite->frames[frame].type == SPR_SINGLE)

-	{

-		pspriteframe = psprite->frames[frame].frameptr;

-	}

-	else

-	{

-		pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;

-		pintervals = pspritegroup->intervals;

-		numframes = pspritegroup->numframes;

-		fullinterval = pintervals[numframes-1];

-

-		time = cl.time + currententity->syncbase;

-

-	// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values

-	// are positive, so we don't have to worry about division by 0

-		targettime = time - ((int)(time / fullinterval)) * fullinterval;

-

-		for (i=0 ; i<(numframes-1) ; i++)

-		{

-			if (pintervals[i] > targettime)

-				break;

-		}

-

-		pspriteframe = pspritegroup->frames[i];

-	}

-

-	return pspriteframe;

-}

-

-

-/*

-=================

-R_DrawSpriteModel

-

-=================

-*/

-void R_DrawSpriteModel (entity_t *e)

-{

-	vec3_t	point;

-	mspriteframe_t	*frame;

-	float		*up, *right;

-	vec3_t		v_forward, v_right, v_up;

-	msprite_t		*psprite;

-

-	// don't even bother culling, because it's just a single

-	// polygon without a surface cache

-	frame = R_GetSpriteFrame (e);

-	psprite = currententity->model->cache.data;

-

-	if (psprite->type == SPR_ORIENTED)

-	{	// bullet marks on walls

-		AngleVectors (currententity->angles, v_forward, v_right, v_up);

-		up = v_up;

-		right = v_right;

-	}

-	else

-	{	// normal sprite

-		up = vup;

-		right = vright;

-	}

-

-	glColor3f (1,1,1);

-

-	GL_DisableMultitexture();

-

-    GL_Bind(frame->gl_texturenum);

-

-	glEnable (GL_ALPHA_TEST);

-	glBegin (GL_QUADS);

-

-	glTexCoord2f (0, 1);

-	VectorMA (e->origin, frame->down, up, point);

-	VectorMA (point, frame->left, right, point);

-	glVertex3fv (point);

-

-	glTexCoord2f (0, 0);

-	VectorMA (e->origin, frame->up, up, point);

-	VectorMA (point, frame->left, right, point);

-	glVertex3fv (point);

-

-	glTexCoord2f (1, 0);

-	VectorMA (e->origin, frame->up, up, point);

-	VectorMA (point, frame->right, right, point);

-	glVertex3fv (point);

-

-	glTexCoord2f (1, 1);

-	VectorMA (e->origin, frame->down, up, point);

-	VectorMA (point, frame->right, right, point);

-	glVertex3fv (point);

-	

-	glEnd ();

-

-	glDisable (GL_ALPHA_TEST);

-}

-

-/*

-=============================================================

-

-  ALIAS MODELS

-

-=============================================================

-*/

-

-

-#define NUMVERTEXNORMALS	162

-

-float	r_avertexnormals[NUMVERTEXNORMALS][3] = {

-#include "anorms.h"

-};

-

-vec3_t	shadevector;

-float	shadelight, ambientlight;

-

-// precalculated dot products for quantized angles

-#define SHADEDOT_QUANT 16

-float	r_avertexnormal_dots[SHADEDOT_QUANT][256] =

-#include "anorm_dots.h"

-;

-

-float	*shadedots = r_avertexnormal_dots[0];

-

-int	lastposenum;

-

-/*

-=============

-GL_DrawAliasFrame

-=============

-*/

-void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum)

-{

-	float	s, t;

-	float 	l;

-	int		i, j;

-	int		index;

-	trivertx_t	*v, *verts;

-	int		list;

-	int		*order;

-	vec3_t	point;

-	float	*normal;

-	int		count;

-

-lastposenum = posenum;

-

-	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);

-	verts += posenum * paliashdr->poseverts;

-	order = (int *)((byte *)paliashdr + paliashdr->commands);

-

-	while (1)

-	{

-		// get the vertex count and primitive type

-		count = *order++;

-		if (!count)

-			break;		// done

-		if (count < 0)

-		{

-			count = -count;

-			glBegin (GL_TRIANGLE_FAN);

-		}

-		else

-			glBegin (GL_TRIANGLE_STRIP);

-

-		do

-		{

-			// texture coordinates come from the draw list

-			glTexCoord2f (((float *)order)[0], ((float *)order)[1]);

-			order += 2;

-

-			// normals and vertexes come from the frame list

-			l = shadedots[verts->lightnormalindex] * shadelight;

-			glColor3f (l, l, l);

-			glVertex3f (verts->v[0], verts->v[1], verts->v[2]);

-			verts++;

-		} while (--count);

-

-		glEnd ();

-	}

-}

-

-

-/*

-=============

-GL_DrawAliasShadow

-=============

-*/

-extern	vec3_t			lightspot;

-

-void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum)

-{

-	float	s, t, l;

-	int		i, j;

-	int		index;

-	trivertx_t	*v, *verts;

-	int		list;

-	int		*order;

-	vec3_t	point;

-	float	*normal;

-	float	height, lheight;

-	int		count;

-

-	lheight = currententity->origin[2] - lightspot[2];

-

-	height = 0;

-	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);

-	verts += posenum * paliashdr->poseverts;

-	order = (int *)((byte *)paliashdr + paliashdr->commands);

-

-	height = -lheight + 1.0;

-

-	while (1)

-	{

-		// get the vertex count and primitive type

-		count = *order++;

-		if (!count)

-			break;		// done

-		if (count < 0)

-		{

-			count = -count;

-			glBegin (GL_TRIANGLE_FAN);

-		}

-		else

-			glBegin (GL_TRIANGLE_STRIP);

-

-		do

-		{

-			// texture coordinates come from the draw list

-			// (skipped for shadows) glTexCoord2fv ((float *)order);

-			order += 2;

-

-			// normals and vertexes come from the frame list

-			point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];

-			point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];

-			point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];

-

-			point[0] -= shadevector[0]*(point[2]+lheight);

-			point[1] -= shadevector[1]*(point[2]+lheight);

-			point[2] = height;

-//			height -= 0.001;

-			glVertex3fv (point);

-

-			verts++;

-		} while (--count);

-

-		glEnd ();

-	}	

-}

-

-

-

-/*

-=================

-R_SetupAliasFrame

-

-=================

-*/

-void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr)

-{

-	int				pose, numposes;

-	float			interval;

-

-	if ((frame >= paliashdr->numframes) || (frame < 0))

-	{

-		Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);

-		frame = 0;

-	}

-

-	pose = paliashdr->frames[frame].firstpose;

-	numposes = paliashdr->frames[frame].numposes;

-

-	if (numposes > 1)

-	{

-		interval = paliashdr->frames[frame].interval;

-		pose += (int)(cl.time / interval) % numposes;

-	}

-

-	GL_DrawAliasFrame (paliashdr, pose);

-}

-

-

-

-/*

-=================

-R_DrawAliasModel

-

-=================

-*/

-void R_DrawAliasModel (entity_t *e)

-{

-	int			i, j;

-	int			lnum;

-	vec3_t		dist;

-	float		add;

-	model_t		*clmodel;

-	vec3_t		mins, maxs;

-	aliashdr_t	*paliashdr;

-	trivertx_t	*verts, *v;

-	int			index;

-	float		s, t, an;

-	int			anim;

-

-	clmodel = currententity->model;

-

-	VectorAdd (currententity->origin, clmodel->mins, mins);

-	VectorAdd (currententity->origin, clmodel->maxs, maxs);

-

-	if (R_CullBox (mins, maxs))

-		return;

-

-

-	VectorCopy (currententity->origin, r_entorigin);

-	VectorSubtract (r_origin, r_entorigin, modelorg);

-

-	//

-	// get lighting information

-	//

-

-	ambientlight = shadelight = R_LightPoint (currententity->origin);

-

-	// allways give the gun some light

-	if (e == &cl.viewent && ambientlight < 24)

-		ambientlight = shadelight = 24;

-

-	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)

-	{

-		if (cl_dlights[lnum].die >= cl.time)

-		{

-			VectorSubtract (currententity->origin,

-							cl_dlights[lnum].origin,

-							dist);

-			add = cl_dlights[lnum].radius - Length(dist);

-

-			if (add > 0) {

-				ambientlight += add;

-				//ZOID models should be affected by dlights as well

-				shadelight += add;

-			}

-		}

-	}

-

-	// clamp lighting so it doesn't overbright as much

-	if (ambientlight > 128)

-		ambientlight = 128;

-	if (ambientlight + shadelight > 192)

-		shadelight = 192 - ambientlight;

-

-	// ZOID: never allow players to go totally black

-	i = currententity - cl_entities;

-	if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)

-		if (ambientlight < 8)

-			ambientlight = shadelight = 8;

-

-	// HACK HACK HACK -- no fullbright colors, so make torches full light

-	if (!strcmp (clmodel->name, "progs/flame2.mdl")

-		|| !strcmp (clmodel->name, "progs/flame.mdl") )

-		ambientlight = shadelight = 256;

-

-	shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];

-	shadelight = shadelight / 200.0;

-	

-	an = e->angles[1]/180*M_PI;

-	shadevector[0] = cos(-an);

-	shadevector[1] = sin(-an);

-	shadevector[2] = 1;

-	VectorNormalize (shadevector);

-

-	//

-	// locate the proper data

-	//

-	paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);

-

-	c_alias_polys += paliashdr->numtris;

-

-	//

-	// draw all the triangles

-	//

-

-	GL_DisableMultitexture();

-

-    glPushMatrix ();

-	R_RotateForEntity (e);

-

-	if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) {

-		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8));

-// double size of eyes, since they are really hard to see in gl

-		glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2);

-	} else {

-		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);

-		glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);

-	}

-

-	anim = (int)(cl.time*10) & 3;

-    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]);

-

-	// we can't dynamically colormap textures, so they are cached

-	// seperately for the players.  Heads are just uncolored.

-	if (currententity->colormap != vid.colormap && !gl_nocolors.value)

-	{

-		i = currententity - cl_entities;

-		if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)

-		    GL_Bind(playertextures - 1 + i);

-	}

-

-	if (gl_smoothmodels.value)

-		glShadeModel (GL_SMOOTH);

-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

-

-	if (gl_affinemodels.value)

-		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);

-

-	R_SetupAliasFrame (currententity->frame, paliashdr);

-

-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

-

-	glShadeModel (GL_FLAT);

-	if (gl_affinemodels.value)

-		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

-

-	glPopMatrix ();

-

-	if (r_shadows.value)

-	{

-		glPushMatrix ();

-		R_RotateForEntity (e);

-		glDisable (GL_TEXTURE_2D);

-		glEnable (GL_BLEND);

-		glColor4f (0,0,0,0.5);

-		GL_DrawAliasShadow (paliashdr, lastposenum);

-		glEnable (GL_TEXTURE_2D);

-		glDisable (GL_BLEND);

-		glColor4f (1,1,1,1);

-		glPopMatrix ();

-	}

-

-}

-

-//==================================================================================

-

-/*

-=============

-R_DrawEntitiesOnList

-=============

-*/

-void R_DrawEntitiesOnList (void)

-{

-	int		i;

-

-	if (!r_drawentities.value)

-		return;

-

-	// draw sprites seperately, because of alpha blending

-	for (i=0 ; i<cl_numvisedicts ; i++)

-	{

-		currententity = cl_visedicts[i];

-

-		switch (currententity->model->type)

-		{

-		case mod_alias:

-			R_DrawAliasModel (currententity);

-			break;

-

-		case mod_brush:

-			R_DrawBrushModel (currententity);

-			break;

-

-		default:

-			break;

-		}

-	}

-

-	for (i=0 ; i<cl_numvisedicts ; i++)

-	{

-		currententity = cl_visedicts[i];

-

-		switch (currententity->model->type)

-		{

-		case mod_sprite:

-			R_DrawSpriteModel (currententity);

-			break;

-		}

-	}

-}

-

-/*

-=============

-R_DrawViewModel

-=============

-*/

-void R_DrawViewModel (void)

-{

-	float		ambient[4], diffuse[4];

-	int			j;

-	int			lnum;

-	vec3_t		dist;

-	float		add;

-	dlight_t	*dl;

-	int			ambientlight, shadelight;

-

-	if (!r_drawviewmodel.value)

-		return;

-

-	if (chase_active.value)

-		return;

-

-	if (envmap)

-		return;

-

-	if (!r_drawentities.value)

-		return;

-

-	if (cl.items & IT_INVISIBILITY)

-		return;

-

-	if (cl.stats[STAT_HEALTH] <= 0)

-		return;

-

-	currententity = &cl.viewent;

-	if (!currententity->model)

-		return;

-

-	j = R_LightPoint (currententity->origin);

-

-	if (j < 24)

-		j = 24;		// allways give some light on gun

-	ambientlight = j;

-	shadelight = j;

-

-// add dynamic lights		

-	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)

-	{

-		dl = &cl_dlights[lnum];

-		if (!dl->radius)

-			continue;

-		if (!dl->radius)

-			continue;

-		if (dl->die < cl.time)

-			continue;

-

-		VectorSubtract (currententity->origin, dl->origin, dist);

-		add = dl->radius - Length(dist);

-		if (add > 0)

-			ambientlight += add;

-	}

-

-	ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128;

-	diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128;

-

-	// hack the depth range to prevent view model from poking into walls

-	glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));

-	R_DrawAliasModel (currententity);

-	glDepthRange (gldepthmin, gldepthmax);

-}

-

-

-/*

-============

-R_PolyBlend

-============

-*/

-void R_PolyBlend (void)

-{

-	if (!gl_polyblend.value)

-		return;

-	if (!v_blend[3])

-		return;

-

-	GL_DisableMultitexture();

-

-	glDisable (GL_ALPHA_TEST);

-	glEnable (GL_BLEND);

-	glDisable (GL_DEPTH_TEST);

-	glDisable (GL_TEXTURE_2D);

-

-    glLoadIdentity ();

-

-    glRotatef (-90,  1, 0, 0);	    // put Z going up

-    glRotatef (90,  0, 0, 1);	    // put Z going up

-

-	glColor4fv (v_blend);

-

-	glBegin (GL_QUADS);

-

-	glVertex3f (10, 100, 100);

-	glVertex3f (10, -100, 100);

-	glVertex3f (10, -100, -100);

-	glVertex3f (10, 100, -100);

-	glEnd ();

-

-	glDisable (GL_BLEND);

-	glEnable (GL_TEXTURE_2D);

-	glEnable (GL_ALPHA_TEST);

-}

-

-

-int SignbitsForPlane (mplane_t *out)

-{

-	int	bits, j;

-

-	// for fast box on planeside test

-

-	bits = 0;

-	for (j=0 ; j<3 ; j++)

-	{

-		if (out->normal[j] < 0)

-			bits |= 1<<j;

-	}

-	return bits;

-}

-

-

-void R_SetFrustum (void)

-{

-	int		i;

-

-	if (r_refdef.fov_x == 90) 

-	{

-		// front side is visible

-

-		VectorAdd (vpn, vright, frustum[0].normal);

-		VectorSubtract (vpn, vright, frustum[1].normal);

-

-		VectorAdd (vpn, vup, frustum[2].normal);

-		VectorSubtract (vpn, vup, frustum[3].normal);

-	}

-	else

-	{

-		// rotate VPN right by FOV_X/2 degrees

-		RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );

-		// rotate VPN left by FOV_X/2 degrees

-		RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );

-		// rotate VPN up by FOV_X/2 degrees

-		RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );

-		// rotate VPN down by FOV_X/2 degrees

-		RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );

-	}

-

-	for (i=0 ; i<4 ; i++)

-	{

-		frustum[i].type = PLANE_ANYZ;

-		frustum[i].dist = DotProduct (r_origin, frustum[i].normal);

-		frustum[i].signbits = SignbitsForPlane (&frustum[i]);

-	}

-}

-

-

-

-/*

-===============

-R_SetupFrame

-===============

-*/

-void R_SetupFrame (void)

-{

-	int				edgecount;

-	vrect_t			vrect;

-	float			w, h;

-

-// don't allow cheats in multiplayer

-	if (cl.maxclients > 1)

-		Cvar_Set ("r_fullbright", "0");

-

-	R_AnimateLight ();

-

-	r_framecount++;

-

-// build the transformation matrix for the given view angles

-	VectorCopy (r_refdef.vieworg, r_origin);

-

-	AngleVectors (r_refdef.viewangles, vpn, vright, vup);

-

-// current viewleaf

-	r_oldviewleaf = r_viewleaf;

-	r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);

-

-	V_SetContentsColor (r_viewleaf->contents);

-	V_CalcBlend ();

-

-	r_cache_thrash = false;

-

-	c_brush_polys = 0;

-	c_alias_polys = 0;

-

-}

-

-

-void MYgluPerspective( GLdouble fovy, GLdouble aspect,

-		     GLdouble zNear, GLdouble zFar )

-{

-   GLdouble xmin, xmax, ymin, ymax;

-

-   ymax = zNear * tan( fovy * M_PI / 360.0 );

-   ymin = -ymax;

-

-   xmin = ymin * aspect;

-   xmax = ymax * aspect;

-

-   glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );

-}

-

-

-/*

-=============

-R_SetupGL

-=============

-*/

-void R_SetupGL (void)

-{

-	float	screenaspect;

-	float	yfov;

-	int		i;

-	extern	int glwidth, glheight;

-	int		x, x2, y2, y, w, h;

-

-	//

-	// set up viewpoint

-	//

-	glMatrixMode(GL_PROJECTION);

-    glLoadIdentity ();

-	x = r_refdef.vrect.x * glwidth/vid.width;

-	x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width;

-	y = (vid.height-r_refdef.vrect.y) * glheight/vid.height;

-	y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height;

-

-	// fudge around because of frac screen scale

-	if (x > 0)

-		x--;

-	if (x2 < glwidth)

-		x2++;

-	if (y2 < 0)

-		y2--;

-	if (y < glheight)

-		y++;

-

-	w = x2 - x;

-	h = y - y2;

-

-	if (envmap)

-	{

-		x = y2 = 0;

-		w = h = 256;

-	}

-

-	glViewport (glx + x, gly + y2, w, h);

-    screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height;

-//	yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;

-    MYgluPerspective (r_refdef.fov_y,  screenaspect,  4,  4096);

-

-	if (mirror)

-	{

-		if (mirror_plane->normal[2])

-			glScalef (1, -1, 1);

-		else

-			glScalef (-1, 1, 1);

-		glCullFace(GL_BACK);

-	}

-	else

-		glCullFace(GL_FRONT);

-

-	glMatrixMode(GL_MODELVIEW);

-    glLoadIdentity ();

-

-    glRotatef (-90,  1, 0, 0);	    // put Z going up

-    glRotatef (90,  0, 0, 1);	    // put Z going up

-    glRotatef (-r_refdef.viewangles[2],  1, 0, 0);

-    glRotatef (-r_refdef.viewangles[0],  0, 1, 0);

-    glRotatef (-r_refdef.viewangles[1],  0, 0, 1);

-    glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);

-

-	glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);

-

-	//

-	// set drawing parms

-	//

-	if (gl_cull.value)

-		glEnable(GL_CULL_FACE);

-	else

-		glDisable(GL_CULL_FACE);

-

-	glDisable(GL_BLEND);

-	glDisable(GL_ALPHA_TEST);

-	glEnable(GL_DEPTH_TEST);

-}

-

-/*

-================

-R_RenderScene

-

-r_refdef must be set before the first call

-================

-*/

-void R_RenderScene (void)

-{

-	R_SetupFrame ();

-

-	R_SetFrustum ();

-

-	R_SetupGL ();

-

-	R_MarkLeaves ();	// done here so we know if we're in water

-

-	R_DrawWorld ();		// adds static entities to the list

-

-	S_ExtraUpdate ();	// don't let sound get messed up if going slow

-

-	R_DrawEntitiesOnList ();

-

-	GL_DisableMultitexture();

-

-	R_RenderDlights ();

-

-	R_DrawParticles ();

-

-#ifdef GLTEST

-	Test_Draw ();

-#endif

-

-}

-

-

-/*

-=============

-R_Clear

-=============

-*/

-void R_Clear (void)

-{

-	if (r_mirroralpha.value != 1.0)

-	{

-		if (gl_clear.value)

-			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

-		else

-			glClear (GL_DEPTH_BUFFER_BIT);

-		gldepthmin = 0;

-		gldepthmax = 0.5;

-		glDepthFunc (GL_LEQUAL);

-	}

-	else if (gl_ztrick.value)

-	{

-		static int trickframe;

-

-		if (gl_clear.value)

-			glClear (GL_COLOR_BUFFER_BIT);

-

-		trickframe++;

-		if (trickframe & 1)

-		{

-			gldepthmin = 0;

-			gldepthmax = 0.49999;

-			glDepthFunc (GL_LEQUAL);

-		}

-		else

-		{

-			gldepthmin = 1;

-			gldepthmax = 0.5;

-			glDepthFunc (GL_GEQUAL);

-		}

-	}

-	else

-	{

-		if (gl_clear.value)

-			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

-		else

-			glClear (GL_DEPTH_BUFFER_BIT);

-		gldepthmin = 0;

-		gldepthmax = 1;

-		glDepthFunc (GL_LEQUAL);

-	}

-

-	glDepthRange (gldepthmin, gldepthmax);

-}

-

-/*

-=============

-R_Mirror

-=============

-*/

-void R_Mirror (void)

-{

-	float		d;

-	msurface_t	*s;

-	entity_t	*ent;

-

-	if (!mirror)

-		return;

-

-	memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix));

-

-	d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist;

-	VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg);

-

-	d = DotProduct (vpn, mirror_plane->normal);

-	VectorMA (vpn, -2*d, mirror_plane->normal, vpn);

-

-	r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180;

-	r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180;

-	r_refdef.viewangles[2] = -r_refdef.viewangles[2];

-

-	ent = &cl_entities[cl.viewentity];

-	if (cl_numvisedicts < MAX_VISEDICTS)

-	{

-		cl_visedicts[cl_numvisedicts] = ent;

-		cl_numvisedicts++;

-	}

-

-	gldepthmin = 0.5;

-	gldepthmax = 1;

-	glDepthRange (gldepthmin, gldepthmax);

-	glDepthFunc (GL_LEQUAL);

-

-	R_RenderScene ();

-	R_DrawWaterSurfaces ();

-

-	gldepthmin = 0;

-	gldepthmax = 0.5;

-	glDepthRange (gldepthmin, gldepthmax);

-	glDepthFunc (GL_LEQUAL);

-

-	// blend on top

-	glEnable (GL_BLEND);

-	glMatrixMode(GL_PROJECTION);

-	if (mirror_plane->normal[2])

-		glScalef (1,-1,1);

-	else

-		glScalef (-1,1,1);

-	glCullFace(GL_FRONT);

-	glMatrixMode(GL_MODELVIEW);

-

-	glLoadMatrixf (r_base_world_matrix);

-

-	glColor4f (1,1,1,r_mirroralpha.value);

-	s = cl.worldmodel->textures[mirrortexturenum]->texturechain;

-	for ( ; s ; s=s->texturechain)

-		R_RenderBrushPoly (s);

-	cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL;

-	glDisable (GL_BLEND);

-	glColor4f (1,1,1,1);

-}

-

-/*

-================

-R_RenderView

-

-r_refdef must be set before the first call

-================

-*/

-void R_RenderView (void)

-{

-	double	time1, time2;

-	GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20};

-

-	if (r_norefresh.value)

-		return;

-

-	if (!r_worldentity.model || !cl.worldmodel)

-		Sys_Error ("R_RenderView: NULL worldmodel");

-

-	if (r_speeds.value)

-	{

-		glFinish ();

-		time1 = Sys_FloatTime ();

-		c_brush_polys = 0;

-		c_alias_polys = 0;

-	}

-

-	mirror = false;

-

-	if (gl_finish.value)

-		glFinish ();

-

-	R_Clear ();

-

-	// render normal view

-

-/***** Experimental silly looking fog ******

-****** Use r_fullbright if you enable ******

-	glFogi(GL_FOG_MODE, GL_LINEAR);

-	glFogfv(GL_FOG_COLOR, colors);

-	glFogf(GL_FOG_END, 512.0);

-	glEnable(GL_FOG);

-********************************************/

-

-	R_RenderScene ();

-	R_DrawViewModel ();

-	R_DrawWaterSurfaces ();

-

-//  More fog right here :)

-//	glDisable(GL_FOG);

-//  End of all fog code...

-

-	// render mirror view

-	R_Mirror ();

-

-	R_PolyBlend ();

-

-	if (r_speeds.value)

-	{

-//		glFinish ();

-		time2 = Sys_FloatTime ();

-		Con_Printf ("%3i ms  %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); 

-	}

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// r_main.c
+
+#include "quakedef.h"
+
+entity_t	r_worldentity;
+
+qboolean	r_cache_thrash;		// compatability
+
+vec3_t		modelorg, r_entorigin;
+entity_t	*currententity;
+
+int			r_visframecount;	// bumped when going to a new PVS
+int			r_framecount;		// used for dlight push checking
+
+mplane_t	frustum[4];
+
+int			c_brush_polys, c_alias_polys;
+
+qboolean	envmap;				// true during envmap command capture 
+
+int			currenttexture = -1;		// to avoid unnecessary texture sets
+
+int			cnttextures[2] = {-1, -1};     // cached
+
+int			particletexture;	// little dot for particles
+int			playertextures;		// up to 16 color translated skins
+
+int			mirrortexturenum;	// quake texturenum, not gltexturenum
+qboolean	mirror;
+mplane_t	*mirror_plane;
+
+//
+// view origin
+//
+vec3_t	vup;
+vec3_t	vpn;
+vec3_t	vright;
+vec3_t	r_origin;
+
+float	r_world_matrix[16];
+float	r_base_world_matrix[16];
+
+//
+// screen size info
+//
+refdef_t	r_refdef;
+
+mleaf_t		*r_viewleaf, *r_oldviewleaf;
+
+texture_t	*r_notexture_mip;
+
+int		d_lightstylevalue[256];	// 8.8 fraction of base light value
+
+
+void R_MarkLeaves (void);
+
+cvar_t	r_norefresh = CVAR2("r_norefresh","0");
+cvar_t	r_drawentities = CVAR2("r_drawentities","1");
+cvar_t	r_drawviewmodel = CVAR2("r_drawviewmodel","1");
+cvar_t	r_speeds = CVAR2("r_speeds","0");
+cvar_t	r_fullbright = CVAR2("r_fullbright","0");
+cvar_t	r_lightmap = CVAR2("r_lightmap","0");
+cvar_t	r_shadows = CVAR2("r_shadows","0");
+cvar_t	r_mirroralpha = CVAR2("r_mirroralpha","1");
+cvar_t	r_wateralpha = CVAR2("r_wateralpha","1");
+cvar_t	r_dynamic = CVAR2("r_dynamic","1");
+cvar_t	r_novis = CVAR2("r_novis","0");
+
+cvar_t	gl_finish = CVAR2("gl_finish","0");
+cvar_t	gl_clear = CVAR2("gl_clear","0");
+cvar_t	gl_cull = CVAR2("gl_cull","1");
+cvar_t	gl_texsort = CVAR2("gl_texsort","1");
+cvar_t	gl_smoothmodels = CVAR2("gl_smoothmodels","1");
+cvar_t	gl_affinemodels = CVAR2("gl_affinemodels","1");
+cvar_t	gl_polyblend = CVAR2("gl_polyblend","1");
+cvar_t	gl_flashblend = CVAR2("gl_flashblend","1");
+cvar_t	gl_playermip = CVAR2("gl_playermip","0");
+cvar_t	gl_nocolors = CVAR2("gl_nocolors","0");
+cvar_t	gl_keeptjunctions = CVAR2("gl_keeptjunctions","1");
+cvar_t	gl_reporttjunctions = CVAR2("gl_reporttjunctions","0");
+cvar_t	gl_doubleeyes = CVAR2("gl_doubleeys", "1");
+
+extern	cvar_t	gl_ztrick;
+
+/*
+=================
+R_CullBox
+
+Returns true if the box is completely outside the frustom
+=================
+*/
+qboolean R_CullBox (vec3_t mins, vec3_t maxs)
+{
+	int		i;
+
+	for (i=0 ; i<4 ; i++)
+		if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2)
+			return true;
+	return false;
+}
+
+
+void R_RotateForEntity (entity_t *e)
+{
+    glTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);
+
+    glRotatef (e->angles[1],  0, 0, 1);
+    glRotatef (-e->angles[0],  0, 1, 0);
+    glRotatef (e->angles[2],  1, 0, 0);
+}
+
+/*
+=============================================================
+
+  SPRITE MODELS
+
+=============================================================
+*/
+
+/*
+================
+R_GetSpriteFrame
+================
+*/
+mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
+{
+	msprite_t		*psprite;
+	mspritegroup_t	*pspritegroup;
+	mspriteframe_t	*pspriteframe;
+	int				i, numframes, frame;
+	float			*pintervals, fullinterval, targettime, time;
+
+	psprite = (msprite_t*) currententity->model->cache.data;
+	frame = currententity->frame;
+
+	if ((frame >= psprite->numframes) || (frame < 0))
+	{
+		Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
+		frame = 0;
+	}
+
+	if (psprite->frames[frame].type == SPR_SINGLE)
+	{
+		pspriteframe = psprite->frames[frame].frameptr;
+	}
+	else
+	{
+		pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
+		pintervals = pspritegroup->intervals;
+		numframes = pspritegroup->numframes;
+		fullinterval = pintervals[numframes-1];
+
+		time = cl.time + currententity->syncbase;
+
+	// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
+	// are positive, so we don't have to worry about division by 0
+		targettime = time - ((int)(time / fullinterval)) * fullinterval;
+
+		for (i=0 ; i<(numframes-1) ; i++)
+		{
+			if (pintervals[i] > targettime)
+				break;
+		}
+
+		pspriteframe = pspritegroup->frames[i];
+	}
+
+	return pspriteframe;
+}
+
+
+/*
+=================
+R_DrawSpriteModel
+
+=================
+*/
+void R_DrawSpriteModel (entity_t *e)
+{
+	vec3_t	point;
+	mspriteframe_t	*frame;
+	float		*up, *right;
+	vec3_t		v_forward, v_right, v_up;
+	msprite_t		*psprite;
+
+	// don't even bother culling, because it's just a single
+	// polygon without a surface cache
+	frame = R_GetSpriteFrame (e);
+	psprite = (msprite_t*) currententity->model->cache.data;
+
+	if (psprite->type == SPR_ORIENTED)
+	{	// bullet marks on walls
+		AngleVectors (currententity->angles, v_forward, v_right, v_up);
+		up = v_up;
+		right = v_right;
+	}
+	else
+	{	// normal sprite
+		up = vup;
+		right = vright;
+	}
+
+	glColor3f (1,1,1);
+
+	GL_DisableMultitexture();
+
+    GL_Bind(frame->gl_texturenum);
+
+	glEnable (GL_ALPHA_TEST);
+
+#ifdef USE_OPENGLES
+
+	{
+	    float* pPoint = gVertexBuffer;
+	    float texCoords[] = {
+			0, 1,
+			0, 0,
+			1, 0,
+			1, 1
+		};
+		
+		VectorMA (e->origin, frame->down, up, point);
+		VectorMA (point, frame->left, right, pPoint);
+		pPoint += 3;
+
+		VectorMA (e->origin, frame->up, up, point);
+		VectorMA (point, frame->left, right, pPoint);
+		pPoint += 3;
+
+		VectorMA (e->origin, frame->up, up, point);
+		VectorMA (point, frame->right, right, pPoint);
+		pPoint += 3;
+
+		VectorMA (e->origin, frame->down, up, point);
+		VectorMA (point, frame->right, right, pPoint);
+		
+		glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
+		glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+	}
+	
+#else
+	glBegin (GL_QUADS);
+
+	glTexCoord2f (0, 1);
+	VectorMA (e->origin, frame->down, up, point);
+	VectorMA (point, frame->left, right, point);
+	glVertex3fv (point);
+
+	glTexCoord2f (0, 0);
+	VectorMA (e->origin, frame->up, up, point);
+	VectorMA (point, frame->left, right, point);
+	glVertex3fv (point);
+
+	glTexCoord2f (1, 0);
+	VectorMA (e->origin, frame->up, up, point);
+	VectorMA (point, frame->right, right, point);
+	glVertex3fv (point);
+
+	glTexCoord2f (1, 1);
+	VectorMA (e->origin, frame->down, up, point);
+	VectorMA (point, frame->right, right, point);
+	glVertex3fv (point);
+	
+	glEnd ();
+#endif
+
+	glDisable (GL_ALPHA_TEST);
+}
+
+/*
+=============================================================
+
+  ALIAS MODELS
+
+=============================================================
+*/
+
+
+#define NUMVERTEXNORMALS	162
+
+float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
+#include "anorms.h"
+};
+
+vec3_t	shadevector;
+float	shadelight, ambientlight;
+
+// precalculated dot products for quantized angles
+#define SHADEDOT_QUANT 16
+float	r_avertexnormal_dots[SHADEDOT_QUANT][256] =
+#include "anorm_dots.h"
+;
+
+float	*shadedots = r_avertexnormal_dots[0];
+
+int	lastposenum;
+
+/*
+=============
+GL_DrawAliasFrame
+=============
+*/
+void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum)
+{
+	float	s, t;
+	float 	l;
+	int		i, j;
+	int		index;
+	trivertx_t	*v, *verts;
+	int		list;
+	int		*order;
+	vec3_t	point;
+	float	*normal;
+	int		count;
+
+#ifdef USE_OPENGLES
+	glEnableClientState(GL_COLOR_ARRAY);
+#endif
+
+lastposenum = posenum;
+
+	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
+	verts += posenum * paliashdr->poseverts;
+	order = (int *)((byte *)paliashdr + paliashdr->commands);
+
+	while (1)
+	{
+		// get the vertex count and primitive type
+		count = *order++;
+		if (!count)
+			break;		// done
+			
+#ifdef USE_OPENGLES
+		{
+			int primType;
+			int c;
+			float* pColor;
+			float* pTexCoord;
+			float* pPos;
+			
+			if (count < 0)
+			{
+				count = -count;
+				primType = GL_TRIANGLE_FAN;
+			}
+			else
+				primType = GL_TRIANGLE_STRIP;
+			
+			// texture coordinates come from the draw list
+			glTexCoordPointer(2, GL_FLOAT, 0, gTexCoordBuffer);
+			glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
+			glColorPointer(3, GL_FLOAT, 0, gColorBuffer);
+		
+			pColor = gColorBuffer;
+			pPos = gVertexBuffer;
+			pTexCoord = gTexCoordBuffer;
+			c = count;
+			do
+			{
+				// texture coordinates come from the draw list
+				*pTexCoord++ = ((float *)order)[0];
+				*pTexCoord++ = ((float *)order)[1];
+				order += 2;
+				
+				// normals and vertexes come from the frame list
+				l = shadedots[verts->lightnormalindex] * shadelight;
+				*pColor++ = l;
+				*pColor++ = l;
+				*pColor++ = l;
+				*pPos++ = verts->v[0];
+				*pPos++ = verts->v[1];
+				*pPos++ = verts->v[2];
+				verts++;
+		    } while (--c);
+									
+			glDrawArrays(primType, 0, count);
+		}
+
+#else
+		if (count < 0)
+		{
+			count = -count;
+			glBegin (GL_TRIANGLE_FAN);
+		}
+		else
+			glBegin (GL_TRIANGLE_STRIP);
+
+		do
+		{
+			// texture coordinates come from the draw list
+			glTexCoord2f (((float *)order)[0], ((float *)order)[1]);
+			order += 2;
+
+			// normals and vertexes come from the frame list
+			l = shadedots[verts->lightnormalindex] * shadelight;
+			glColor3f (l, l, l);
+			glVertex3f (verts->v[0], verts->v[1], verts->v[2]);
+			verts++;
+		} while (--count);
+
+		glEnd ();
+#endif
+	}
+
+#ifdef USE_OPENGLES
+	glDisableClientState(GL_COLOR_ARRAY);
+#endif
+
+}
+
+
+/*
+=============
+GL_DrawAliasShadow
+=============
+*/
+extern	vec3_t			lightspot;
+
+void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum)
+{
+	float	s, t, l;
+	int		i, j;
+	int		index;
+	trivertx_t	*v, *verts;
+	int		list;
+	int		*order;
+	vec3_t	point;
+	float	*normal;
+	float	height, lheight;
+	int		count;
+
+	lheight = currententity->origin[2] - lightspot[2];
+
+	height = 0;
+	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
+	verts += posenum * paliashdr->poseverts;
+	order = (int *)((byte *)paliashdr + paliashdr->commands);
+
+	height = -lheight + 1.0;
+
+	while (1)
+	{
+		// get the vertex count and primitive type
+		count = *order++;
+		if (!count)
+			break;		// done
+			
+#ifdef USE_OPENGLES
+
+		{
+			int primType;
+			int c;
+			float* pVertex;
+			
+			if (count < 0)
+			{
+				count = -count;
+				primType = GL_TRIANGLE_FAN;
+			}
+			else
+				primType = GL_TRIANGLE_STRIP;
+					
+			pVertex = gVertexBuffer;
+			for(c = 0; c < count; c++)
+			{
+				// texture coordinates come from the draw list
+				// (skipped for shadows) glTexCoord2fv ((float *)order);
+				order += 2;
+
+				// normals and vertexes come from the frame list
+				pVertex[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
+				pVertex[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
+				pVertex[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];
+
+				pVertex[0] -= shadevector[0]*(pVertex[2]+lheight);
+				pVertex[1] -= shadevector[1]*(pVertex[2]+lheight);
+				pVertex[2] = height;
+	//			height -= 0.001;
+	
+				pVertex += 3;
+				verts++;
+			}
+			
+			glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
+			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+			glDrawArrays(primType, 0, count);
+			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		}
+
+#else
+
+		if (count < 0)
+		{
+			count = -count;
+			glBegin (GL_TRIANGLE_FAN);
+		}
+		else
+			glBegin (GL_TRIANGLE_STRIP);
+
+		do
+		{
+			// texture coordinates come from the draw list
+			// (skipped for shadows) glTexCoord2fv ((float *)order);
+			order += 2;
+
+			// normals and vertexes come from the frame list
+			point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
+			point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
+			point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];
+
+			point[0] -= shadevector[0]*(point[2]+lheight);
+			point[1] -= shadevector[1]*(point[2]+lheight);
+			point[2] = height;
+//			height -= 0.001;
+			glVertex3fv (point);
+
+			verts++;
+		} while (--count);
+
+		glEnd ();
+		
+#endif
+
+	}	
+}
+
+
+
+/*
+=================
+R_SetupAliasFrame
+
+=================
+*/
+void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr)
+{
+	int				pose, numposes;
+	float			interval;
+
+	if ((frame >= paliashdr->numframes) || (frame < 0))
+	{
+		Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
+		frame = 0;
+	}
+
+	pose = paliashdr->frames[frame].firstpose;
+	numposes = paliashdr->frames[frame].numposes;
+
+	if (numposes > 1)
+	{
+		interval = paliashdr->frames[frame].interval;
+		pose += (int)(cl.time / interval) % numposes;
+	}
+
+	GL_DrawAliasFrame (paliashdr, pose);
+}
+
+
+
+/*
+=================
+R_DrawAliasModel
+
+=================
+*/
+void R_DrawAliasModel (entity_t *e)
+{
+	int			i, j;
+	int			lnum;
+	vec3_t		dist;
+	float		add;
+	model_t		*clmodel;
+	vec3_t		mins, maxs;
+	aliashdr_t	*paliashdr;
+	trivertx_t	*verts, *v;
+	int			index;
+	float		s, t, an;
+	int			anim;
+
+	clmodel = currententity->model;
+
+	VectorAdd (currententity->origin, clmodel->mins, mins);
+	VectorAdd (currententity->origin, clmodel->maxs, maxs);
+
+	if (R_CullBox (mins, maxs))
+		return;
+
+
+	VectorCopy (currententity->origin, r_entorigin);
+	VectorSubtract (r_origin, r_entorigin, modelorg);
+
+	//
+	// get lighting information
+	//
+
+	ambientlight = shadelight = R_LightPoint (currententity->origin);
+
+	// allways give the gun some light
+	if (e == &cl.viewent && ambientlight < 24)
+		ambientlight = shadelight = 24;
+
+	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
+	{
+		if (cl_dlights[lnum].die >= cl.time)
+		{
+			VectorSubtract (currententity->origin,
+							cl_dlights[lnum].origin,
+							dist);
+			add = cl_dlights[lnum].radius - Length(dist);
+
+			if (add > 0) {
+				ambientlight += add;
+				//ZOID models should be affected by dlights as well
+				shadelight += add;
+			}
+		}
+	}
+
+	// clamp lighting so it doesn't overbright as much
+	if (ambientlight > 128)
+		ambientlight = 128;
+	if (ambientlight + shadelight > 192)
+		shadelight = 192 - ambientlight;
+
+	// ZOID: never allow players to go totally black
+	i = currententity - cl_entities;
+	if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
+		if (ambientlight < 8)
+			ambientlight = shadelight = 8;
+
+	// HACK HACK HACK -- no fullbright colors, so make torches full light
+	if (!strcmp (clmodel->name, "progs/flame2.mdl")
+		|| !strcmp (clmodel->name, "progs/flame.mdl") )
+		ambientlight = shadelight = 256;
+
+	shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
+	shadelight = shadelight / 200.0;
+	
+	an = e->angles[1]/180*M_PI;
+	shadevector[0] = cos(-an);
+	shadevector[1] = sin(-an);
+	shadevector[2] = 1;
+	VectorNormalize (shadevector);
+
+	//
+	// locate the proper data
+	//
+	paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
+
+	c_alias_polys += paliashdr->numtris;
+
+	//
+	// draw all the triangles
+	//
+
+	GL_DisableMultitexture();
+
+    glPushMatrix ();
+	R_RotateForEntity (e);
+
+	if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) {
+		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8));
+// double size of eyes, since they are really hard to see in gl
+		glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2);
+	} else {
+		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
+		glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
+	}
+
+	anim = (int)(cl.time*10) & 3;
+    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]);
+
+	// we can't dynamically colormap textures, so they are cached
+	// seperately for the players.  Heads are just uncolored.
+	if (currententity->colormap != vid.colormap && !gl_nocolors.value)
+	{
+		i = currententity - cl_entities;
+		if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
+		    GL_Bind(playertextures - 1 + i);
+	}
+
+	if (gl_smoothmodels.value)
+		glShadeModel (GL_SMOOTH);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+	if (gl_affinemodels.value)
+		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+
+	R_SetupAliasFrame (currententity->frame, paliashdr);
+
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+	glShadeModel (GL_FLAT);
+	if (gl_affinemodels.value)
+		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+	glPopMatrix ();
+
+	if (r_shadows.value)
+	{
+		glPushMatrix ();
+		R_RotateForEntity (e);
+		glDisable (GL_TEXTURE_2D);
+		glEnable (GL_BLEND);
+		glColor4f (0,0,0,0.5);
+		GL_DrawAliasShadow (paliashdr, lastposenum);
+		glEnable (GL_TEXTURE_2D);
+		glDisable (GL_BLEND);
+		glColor4f (1,1,1,1);
+		glPopMatrix ();
+	}
+
+}
+
+//==================================================================================
+
+/*
+=============
+R_DrawEntitiesOnList
+=============
+*/
+void R_DrawEntitiesOnList (void)
+{
+	int		i;
+
+	if (!r_drawentities.value)
+		return;
+
+	// draw sprites seperately, because of alpha blending
+	for (i=0 ; i<cl_numvisedicts ; i++)
+	{
+		currententity = cl_visedicts[i];
+
+		switch (currententity->model->type)
+		{
+		case mod_alias:
+			R_DrawAliasModel (currententity);
+			break;
+
+		case mod_brush:
+			R_DrawBrushModel (currententity);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	for (i=0 ; i<cl_numvisedicts ; i++)
+	{
+		currententity = cl_visedicts[i];
+
+		switch (currententity->model->type)
+		{
+		case mod_sprite:
+			R_DrawSpriteModel (currententity);
+			break;
+
+		default :
+			break;
+		}
+	}
+}
+
+/*
+=============
+R_DrawViewModel
+=============
+*/
+void R_DrawViewModel (void)
+{
+	float		ambient[4], diffuse[4];
+	int			j;
+	int			lnum;
+	vec3_t		dist;
+	float		add;
+	dlight_t	*dl;
+	int			ambientlight, shadelight;
+
+	if (!r_drawviewmodel.value)
+		return;
+
+	if (chase_active.value)
+		return;
+
+	if (envmap)
+		return;
+
+	if (!r_drawentities.value)
+		return;
+
+	if (cl.items & IT_INVISIBILITY)
+		return;
+
+	if (cl.stats[STAT_HEALTH] <= 0)
+		return;
+
+	currententity = &cl.viewent;
+	if (!currententity->model)
+		return;
+
+	j = R_LightPoint (currententity->origin);
+
+	if (j < 24)
+		j = 24;		// allways give some light on gun
+	ambientlight = j;
+	shadelight = j;
+
+// add dynamic lights		
+	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
+	{
+		dl = &cl_dlights[lnum];
+		if (!dl->radius)
+			continue;
+		if (!dl->radius)
+			continue;
+		if (dl->die < cl.time)
+			continue;
+
+		VectorSubtract (currententity->origin, dl->origin, dist);
+		add = dl->radius - Length(dist);
+		if (add > 0)
+			ambientlight += (int) add;
+	}
+
+	ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128;
+	diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128;
+
+	// hack the depth range to prevent view model from poking into walls
+#ifdef USE_OPENGLES
+	glDepthRangef(gldepthmin, gldepthmin + 0.3f*(gldepthmax-gldepthmin));
+	R_DrawAliasModel (currententity);
+	glDepthRangef(gldepthmin, gldepthmax);
+#else
+	glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
+	R_DrawAliasModel (currententity);
+	glDepthRange (gldepthmin, gldepthmax);
+#endif
+}
+
+
+/*
+============
+R_PolyBlend
+============
+*/
+void R_PolyBlend (void)
+{
+	if (!gl_polyblend.value)
+		return;
+	if (!v_blend[3])
+		return;
+
+	GL_DisableMultitexture();
+
+	glDisable (GL_ALPHA_TEST);
+	glEnable (GL_BLEND);
+	glDisable (GL_DEPTH_TEST);
+	glDisable (GL_TEXTURE_2D);
+
+    glLoadIdentity ();
+
+    glRotatef (-90,  1, 0, 0);	    // put Z going up
+    glRotatef (90,  0, 0, 1);	    // put Z going up
+
+	glColor4fv (v_blend);
+
+#ifdef USE_OPENGLES
+	float vertex[3*4] = {
+		10, 100, 100,
+		10, -100, 100,
+		10, -100, -100,
+		10, 100, -100
+	};
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glVertexPointer( 3, GL_FLOAT, 0, vertex);
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+#else
+	glBegin (GL_QUADS);
+
+	glVertex3f (10, 100, 100);
+	glVertex3f (10, -100, 100);
+	glVertex3f (10, -100, -100);
+	glVertex3f (10, 100, -100);
+	glEnd ();
+#endif
+
+	glDisable (GL_BLEND);
+	glEnable (GL_TEXTURE_2D);
+	glEnable (GL_ALPHA_TEST);
+}
+
+
+int SignbitsForPlane (mplane_t *out)
+{
+	int	bits, j;
+
+	// for fast box on planeside test
+
+	bits = 0;
+	for (j=0 ; j<3 ; j++)
+	{
+		if (out->normal[j] < 0)
+			bits |= 1<<j;
+	}
+	return bits;
+}
+
+
+void R_SetFrustum (void)
+{
+	int		i;
+
+	if (r_refdef.fov_x == 90) 
+	{
+		// front side is visible
+
+		VectorAdd (vpn, vright, frustum[0].normal);
+		VectorSubtract (vpn, vright, frustum[1].normal);
+
+		VectorAdd (vpn, vup, frustum[2].normal);
+		VectorSubtract (vpn, vup, frustum[3].normal);
+	}
+	else
+	{
+		// rotate VPN right by FOV_X/2 degrees
+		RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
+		// rotate VPN left by FOV_X/2 degrees
+		RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
+		// rotate VPN up by FOV_X/2 degrees
+		RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
+		// rotate VPN down by FOV_X/2 degrees
+		RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
+	}
+
+	for (i=0 ; i<4 ; i++)
+	{
+		frustum[i].type = PLANE_ANYZ;
+		frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
+		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
+	}
+}
+
+
+
+/*
+===============
+R_SetupFrame
+===============
+*/
+void R_SetupFrame (void)
+{
+	int				edgecount;
+	vrect_t			vrect;
+	float			w, h;
+
+// don't allow cheats in multiplayer
+	if (cl.maxclients > 1)
+		Cvar_Set ("r_fullbright", "0");
+
+	R_AnimateLight ();
+
+	r_framecount++;
+
+// build the transformation matrix for the given view angles
+	VectorCopy (r_refdef.vieworg, r_origin);
+
+	AngleVectors (r_refdef.viewangles, vpn, vright, vup);
+
+// current viewleaf
+	r_oldviewleaf = r_viewleaf;
+	r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
+
+	V_SetContentsColor (r_viewleaf->contents);
+	V_CalcBlend ();
+
+	r_cache_thrash = false;
+
+	c_brush_polys = 0;
+	c_alias_polys = 0;
+
+}
+
+#ifdef USE_OPENGLES
+
+void MYgluPerspective( float fovy, float aspect,
+		     float zNear, float zFar )
+{
+   float xmin, xmax, ymin, ymax;
+
+   ymax = zNear * tan( fovy * M_PI / 360.0f );
+   ymin = -ymax;
+
+   xmin = ymin * aspect;
+   xmax = ymax * aspect;
+
+   glFrustumf( xmin, xmax, ymin, ymax, zNear, zFar );
+}
+
+#else
+
+void MYgluPerspective( GLdouble fovy, GLdouble aspect,
+		     GLdouble zNear, GLdouble zFar )
+{
+   GLdouble xmin, xmax, ymin, ymax;
+
+   ymax = zNear * tan( fovy * M_PI / 360.0 );
+   ymin = -ymax;
+
+   xmin = ymin * aspect;
+   xmax = ymax * aspect;
+
+   glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
+}
+#endif
+
+#define DO_OWN_MATRIX_MATH
+#ifdef DO_OWN_MATRIX_MATH
+// We can't count on being able to read back the model view matrix, so calculate it ourselves.
+
+#define I(_i, _j) ((_j)+ 4*(_i))
+
+void mulMM(float* r, const float* lhs, const float* rhs)
+{
+    float const* const m = lhs;
+    for (int i=0 ; i<4 ; i++) {
+        register const float rhs_i0 = rhs[ I(i,0) ];
+        register float ri0 = m[ I(0,0) ] * rhs_i0;
+        register float ri1 = m[ I(0,1) ] * rhs_i0;
+        register float ri2 = m[ I(0,2) ] * rhs_i0;
+        register float ri3 = m[ I(0,3) ] * rhs_i0;
+        for (int j=1 ; j<4 ; j++) {
+            register const float rhs_ij = rhs[ I(i,j) ];
+            ri0 += m[ I(j,0) ] * rhs_ij;
+            ri1 += m[ I(j,1) ] * rhs_ij;
+            ri2 += m[ I(j,2) ] * rhs_ij;
+            ri3 += m[ I(j,3) ] * rhs_ij;
+        }
+        r[ I(i,0) ] = ri0;
+        r[ I(i,1) ] = ri1;
+        r[ I(i,2) ] = ri2;
+        r[ I(i,3) ] = ri3;
+    }
+}
+
+static void setIdentityM(float* sm, int smOffset) {
+    for (int i=0 ; i<16 ; i++) {
+        sm[smOffset + i] = 0;
+    }
+    for(int i = 0; i < 16; i += 5) {
+        sm[smOffset + i] = 1.0f;
+    }
+}
+
+static void translateM(float* m, int mOffset,
+        float x, float y, float z) {
+    for (int i=0 ; i<4 ; i++) {
+        int mi = mOffset + i;
+        m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;
+    }
+}
+
+static float length(float x, float y, float z) {
+	return (float) sqrtf(x * x + y * y + z * z);
+}
+
+static void setRotateM(float* rm, int rmOffset,
+            float a, float x, float y, float z)
+{
+    rm[rmOffset + 3] = 0;
+    rm[rmOffset + 7] = 0;
+    rm[rmOffset + 11]= 0;
+    rm[rmOffset + 12]= 0;
+    rm[rmOffset + 13]= 0;
+    rm[rmOffset + 14]= 0;
+    rm[rmOffset + 15]= 1;
+    a *= (float) (M_PI / 180.0f);
+    float s = (float) sinf(a);
+    float c = (float) cosf(a);
+    if (1.0f == x && 0.0f == y && 0.0f == z) {
+        rm[rmOffset + 5] = c;   rm[rmOffset + 10]= c;
+        rm[rmOffset + 6] = s;   rm[rmOffset + 9] = -s;
+        rm[rmOffset + 1] = 0;   rm[rmOffset + 2] = 0;
+        rm[rmOffset + 4] = 0;   rm[rmOffset + 8] = 0;
+        rm[rmOffset + 0] = 1;
+    } else if (0.0f == x && 1.0f == y && 0.0f == z) {
+        rm[rmOffset + 0] = c;   rm[rmOffset + 10]= c;
+        rm[rmOffset + 8] = s;   rm[rmOffset + 2] = -s;
+        rm[rmOffset + 1] = 0;   rm[rmOffset + 4] = 0;
+        rm[rmOffset + 6] = 0;   rm[rmOffset + 9] = 0;
+        rm[rmOffset + 5] = 1;
+    } else if (0.0f == x && 0.0f == y && 1.0f == z) {
+        rm[rmOffset + 0] = c;   rm[rmOffset + 5] = c;
+        rm[rmOffset + 1] = s;   rm[rmOffset + 4] = -s;
+        rm[rmOffset + 2] = 0;   rm[rmOffset + 6] = 0;
+        rm[rmOffset + 8] = 0;   rm[rmOffset + 9] = 0;
+        rm[rmOffset + 10]= 1;
+    } else {
+        float len = length(x, y, z);
+        if (1.0f != len) {
+            float recipLen = 1.0f / len;
+            x *= recipLen;
+            y *= recipLen;
+            z *= recipLen;
+        }
+        float nc = 1.0f - c;
+        float xy = x * y;
+        float yz = y * z;
+        float zx = z * x;
+        float xs = x * s;
+        float ys = y * s;
+        float zs = z * s;       
+        rm[rmOffset +  0] = x*x*nc +  c;
+        rm[rmOffset +  4] =  xy*nc - zs;
+        rm[rmOffset +  8] =  zx*nc + ys;
+        rm[rmOffset +  1] =  xy*nc + zs;
+        rm[rmOffset +  5] = y*y*nc +  c;
+        rm[rmOffset +  9] =  yz*nc - xs;
+        rm[rmOffset +  2] =  zx*nc - ys;
+        rm[rmOffset +  6] =  yz*nc + xs;
+        rm[rmOffset + 10] = z*z*nc +  c;
+    }
+}
+
+static void rotateM(float* m,
+            float a, float x, float y, float z) {
+    float temp[16];
+    float temp2[16];
+    setRotateM(temp, 0, a, x, y, z);
+    mulMM(temp2, m, temp);
+    memcpy(m, temp2, 16 * sizeof(float));
+}
+
+#undef I
+
+#endif // DO_OWN_MATRIX_MATH
+
+/*
+=============
+R_SetupGL
+=============
+*/
+void R_SetupGL (void)
+{
+	float	screenaspect;
+	float	yfov;
+	int		i;
+	extern	int glwidth, glheight;
+	int		x, x2, y2, y, w, h;
+
+	//
+	// set up viewpoint
+	//
+	glMatrixMode(GL_PROJECTION);
+    glLoadIdentity ();
+	x = r_refdef.vrect.x * glwidth/vid.width;
+	x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width;
+	y = (vid.height-r_refdef.vrect.y) * glheight/vid.height;
+	y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height;
+
+	// fudge around because of frac screen scale
+	if (x > 0)
+		x--;
+	if (x2 < glwidth)
+		x2++;
+	if (y2 < 0)
+		y2--;
+	if (y < glheight)
+		y++;
+
+	w = x2 - x;
+	h = y - y2;
+
+	if (envmap)
+	{
+		x = y2 = 0;
+		w = h = 256;
+	}
+
+	glViewport (glx + x, gly + y2, w, h);
+    screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height;
+//	yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;
+    MYgluPerspective (r_refdef.fov_y,  screenaspect,  4,  4096);
+
+	if (mirror)
+	{
+		if (mirror_plane->normal[2])
+			glScalef (1, -1, 1);
+		else
+			glScalef (-1, 1, 1);
+		glCullFace(GL_BACK);
+	}
+	else
+		glCullFace(GL_FRONT);
+
+	glMatrixMode(GL_MODELVIEW);
+	
+#ifdef DO_OWN_MATRIX_MATH
+
+	float mv[16];
+    setIdentityM(mv, 0);
+
+    rotateM(mv, -90,  1, 0, 0);	    // put Z going up
+    rotateM(mv, 90,  0, 0, 1);	    // put Z going up
+    rotateM(mv, -r_refdef.viewangles[2],  1, 0, 0);
+    rotateM(mv, -r_refdef.viewangles[0],  0, 1, 0);
+    rotateM(mv, -r_refdef.viewangles[1],  0, 0, 1);
+    translateM(mv, 0, -r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);
+
+    glLoadMatrixf(mv);
+    
+    memcpy(r_world_matrix, mv, sizeof(r_world_matrix));
+
+#else
+    glLoadIdentity ();
+
+    glRotatef (-90,  1, 0, 0);	    // put Z going up
+    glRotatef (90,  0, 0, 1);	    // put Z going up
+    glRotatef (-r_refdef.viewangles[2],  1, 0, 0);
+    glRotatef (-r_refdef.viewangles[0],  0, 1, 0);
+    glRotatef (-r_refdef.viewangles[1],  0, 0, 1);
+    glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);
+
+#ifdef USE_OPENGLES
+
+    static qboolean initialized;
+    static qboolean haveGL_OES_matrix_get;
+    static qboolean haveGL_OES_query_matrix;
+
+#if 0
+    if (! initialized) {
+        const char* extensions = (const char*) glGetString(GL_EXTENSIONS);
+        haveGL_OES_matrix_get =
+            strstr(extensions, "GL_OES_matrix_get") != NULL;
+        haveGL_OES_query_matrix =
+            strstr(extensions, "GL_OES_query_matrix") != NULL;
+        initialized = true;
+    }
+    if (haveGL_OES_query_matrix) {
+        GLfixed mantissa[16];
+        GLint exponent[16];
+        glQueryMatrixxOES( mantissa, exponent );
+        for(int i = 0; i < 16; i++) {
+            r_world_matrix[i] = scalbnf(mantissa[i], exponent[i]-16);
+        }
+    }
+    else if (haveGL_OES_matrix_get) {
+        glGetIntegerv (MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,
+                (GLint*) r_world_matrix);
+    }
+    else
+#endif
+    	{
+        // No way to get the world matix, set to identity
+        memset(r_world_matrix, 0, sizeof(r_world_matrix));
+        for(i = 0; i < 16; i += 5) {
+            r_world_matrix[i] = 1.0f;
+        }
+    }
+#else
+	glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
+#endif
+#endif // DO_OWN_MATRIX_MATH
+	//
+	// set drawing parms
+	//
+	if (gl_cull.value)
+		glEnable(GL_CULL_FACE);
+	else
+		glDisable(GL_CULL_FACE);
+
+	glDisable(GL_BLEND);
+	glDisable(GL_ALPHA_TEST);
+	glEnable(GL_DEPTH_TEST);
+}
+
+/*
+================
+R_RenderScene
+
+r_refdef must be set before the first call
+================
+*/
+void R_RenderScene (void)
+{
+	R_SetupFrame ();
+
+	R_SetFrustum ();
+
+	R_SetupGL ();
+
+	R_MarkLeaves ();	// done here so we know if we're in water
+
+	R_DrawWorld ();		// adds static entities to the list
+
+	S_ExtraUpdate ();	// don't let sound get messed up if going slow
+
+	R_DrawEntitiesOnList ();
+
+	GL_DisableMultitexture();
+
+	R_RenderDlights ();
+
+	R_DrawParticles ();
+
+#ifdef GLTEST
+	Test_Draw ();
+#endif
+
+}
+
+
+/*
+=============
+R_Clear
+=============
+*/
+void R_Clear (void)
+{
+	if (r_mirroralpha.value != 1.0)
+	{
+		if (gl_clear.value)
+			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		else
+			glClear (GL_DEPTH_BUFFER_BIT);
+		gldepthmin = 0;
+		gldepthmax = 0.5;
+		glDepthFunc (GL_LEQUAL);
+	}
+	else if (gl_ztrick.value)
+	{
+		static int trickframe;
+
+		if (gl_clear.value)
+			glClear (GL_COLOR_BUFFER_BIT);
+
+		trickframe++;
+		if (trickframe & 1)
+		{
+			gldepthmin = 0;
+			gldepthmax = 0.49999;
+			glDepthFunc (GL_LEQUAL);
+		}
+		else
+		{
+			gldepthmin = 1;
+			gldepthmax = 0.5;
+			glDepthFunc (GL_GEQUAL);
+		}
+	}
+	else
+	{
+		if (gl_clear.value)
+			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		else
+			glClear (GL_DEPTH_BUFFER_BIT);
+		gldepthmin = 0;
+		gldepthmax = 1;
+		glDepthFunc (GL_LEQUAL);
+	}
+
+#ifdef USE_OPENGLES
+	glDepthRangef (gldepthmin, gldepthmax);
+#else
+	glDepthRange (gldepthmin, gldepthmax);
+#endif
+}
+
+/*
+=============
+R_Mirror
+=============
+*/
+void R_Mirror (void)
+{
+	float		d;
+	msurface_t	*s;
+	entity_t	*ent;
+
+	if (!mirror)
+		return;
+
+	memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix));
+
+	d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist;
+	VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg);
+
+	d = DotProduct (vpn, mirror_plane->normal);
+	VectorMA (vpn, -2*d, mirror_plane->normal, vpn);
+
+	r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180;
+	r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180;
+	r_refdef.viewangles[2] = -r_refdef.viewangles[2];
+
+	ent = &cl_entities[cl.viewentity];
+	if (cl_numvisedicts < MAX_VISEDICTS)
+	{
+		cl_visedicts[cl_numvisedicts] = ent;
+		cl_numvisedicts++;
+	}
+
+	gldepthmin = 0.5;
+	gldepthmax = 1;
+#ifdef USE_OPENGLES
+	glDepthRangef (gldepthmin, gldepthmax);
+#else
+	glDepthRange (gldepthmin, gldepthmax);
+#endif
+	glDepthFunc (GL_LEQUAL);
+
+	R_RenderScene ();
+	R_DrawWaterSurfaces ();
+
+	gldepthmin = 0;
+	gldepthmax = 0.5;
+#ifdef USE_OPENGLES
+	glDepthRangef (gldepthmin, gldepthmax);
+#else
+	glDepthRange (gldepthmin, gldepthmax);
+#endif
+	glDepthFunc (GL_LEQUAL);
+
+	// blend on top
+	glEnable (GL_BLEND);
+	glMatrixMode(GL_PROJECTION);
+	if (mirror_plane->normal[2])
+		glScalef (1,-1,1);
+	else
+		glScalef (-1,1,1);
+	glCullFace(GL_FRONT);
+	glMatrixMode(GL_MODELVIEW);
+
+	glLoadMatrixf (r_base_world_matrix);
+
+	glColor4f (1,1,1,r_mirroralpha.value);
+	s = cl.worldmodel->textures[mirrortexturenum]->texturechain;
+	for ( ; s ; s=s->texturechain)
+		R_RenderBrushPoly (s);
+	cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL;
+	glDisable (GL_BLEND);
+	glColor4f (1,1,1,1);
+}
+
+/*
+================
+R_RenderView
+
+r_refdef must be set before the first call
+================
+*/
+void R_RenderView (void)
+{
+	double time1 = 0.0;
+	double time2;
+	GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20};
+
+	if (r_norefresh.value)
+		return;
+
+	if (!r_worldentity.model || !cl.worldmodel)
+		Sys_Error ("R_RenderView: NULL worldmodel");
+
+	if (r_speeds.value)
+	{
+		glFinish ();
+		time1 = Sys_FloatTime ();
+		c_brush_polys = 0;
+		c_alias_polys = 0;
+	}
+
+	mirror = false;
+
+	if (gl_finish.value)
+		glFinish ();
+
+	R_Clear ();
+
+	// render normal view
+
+/***** Experimental silly looking fog ******
+****** Use r_fullbright if you enable ******
+	glFogi(GL_FOG_MODE, GL_LINEAR);
+	glFogfv(GL_FOG_COLOR, colors);
+	glFogf(GL_FOG_END, 512.0);
+	glEnable(GL_FOG);
+********************************************/
+
+	R_RenderScene ();
+	R_DrawViewModel ();
+	R_DrawWaterSurfaces ();
+
+//  More fog right here :)
+//	glDisable(GL_FOG);
+//  End of all fog code...
+
+	// render mirror view
+	R_Mirror ();
+
+	R_PolyBlend ();
+
+	if (r_speeds.value)
+	{
+//		glFinish ();
+		time2 = Sys_FloatTime ();
+		Con_Printf ("%3i ms  %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); 
+	}
+}
diff --git a/quake/src/WinQuake/gl_rmisc.c b/quake/src/WinQuake/gl_rmisc.c
deleted file mode 100644
index caffd83..0000000
--- a/quake/src/WinQuake/gl_rmisc.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// r_misc.c
-
-#include "quakedef.h"
-
-
-
-/*
-==================
-R_InitTextures
-==================
-*/
-void	R_InitTextures (void)
-{
-	int		x,y, m;
-	byte	*dest;
-
-// create a simple checkerboard texture for the default
-	r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture");
-	
-	r_notexture_mip->width = r_notexture_mip->height = 16;
-	r_notexture_mip->offsets[0] = sizeof(texture_t);
-	r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
-	r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
-	r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
-	
-	for (m=0 ; m<4 ; m++)
-	{
-		dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
-		for (y=0 ; y< (16>>m) ; y++)
-			for (x=0 ; x< (16>>m) ; x++)
-			{
-				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
-					*dest++ = 0;
-				else
-					*dest++ = 0xff;
-			}
-	}	
-}
-
-byte	dottexture[8][8] =
-{
-	{0,1,1,0,0,0,0,0},
-	{1,1,1,1,0,0,0,0},
-	{1,1,1,1,0,0,0,0},
-	{0,1,1,0,0,0,0,0},
-	{0,0,0,0,0,0,0,0},
-	{0,0,0,0,0,0,0,0},
-	{0,0,0,0,0,0,0,0},
-	{0,0,0,0,0,0,0,0},
-};
-void R_InitParticleTexture (void)
-{
-	int		x,y;
-	byte	data[8][8][4];
-
-	//
-	// particle texture
-	//
-	particletexture = texture_extension_number++;
-    GL_Bind(particletexture);
-
-	for (x=0 ; x<8 ; x++)
-	{
-		for (y=0 ; y<8 ; y++)
-		{
-			data[y][x][0] = 255;
-			data[y][x][1] = 255;
-			data[y][x][2] = 255;
-			data[y][x][3] = dottexture[x][y]*255;
-		}
-	}
-	glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-
-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-}
-
-/*
-===============
-R_Envmap_f
-
-Grab six views for environment mapping tests
-===============
-*/
-void R_Envmap_f (void)
-{
-	byte	buffer[256*256*4];
-	char	name[1024];
-
-	glDrawBuffer  (GL_FRONT);
-	glReadBuffer  (GL_FRONT);
-	envmap = true;
-
-	r_refdef.vrect.x = 0;
-	r_refdef.vrect.y = 0;
-	r_refdef.vrect.width = 256;
-	r_refdef.vrect.height = 256;
-
-	r_refdef.viewangles[0] = 0;
-	r_refdef.viewangles[1] = 0;
-	r_refdef.viewangles[2] = 0;
-	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-	R_RenderView ();
-	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-	COM_WriteFile ("env0.rgb", buffer, sizeof(buffer));		
-
-	r_refdef.viewangles[1] = 90;
-	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-	R_RenderView ();
-	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-	COM_WriteFile ("env1.rgb", buffer, sizeof(buffer));		
-
-	r_refdef.viewangles[1] = 180;
-	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-	R_RenderView ();
-	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-	COM_WriteFile ("env2.rgb", buffer, sizeof(buffer));		
-
-	r_refdef.viewangles[1] = 270;
-	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-	R_RenderView ();
-	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-	COM_WriteFile ("env3.rgb", buffer, sizeof(buffer));		
-
-	r_refdef.viewangles[0] = -90;
-	r_refdef.viewangles[1] = 0;
-	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-	R_RenderView ();
-	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-	COM_WriteFile ("env4.rgb", buffer, sizeof(buffer));		
-
-	r_refdef.viewangles[0] = 90;
-	r_refdef.viewangles[1] = 0;
-	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-	R_RenderView ();
-	glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-	COM_WriteFile ("env5.rgb", buffer, sizeof(buffer));		
-
-	envmap = false;
-	glDrawBuffer  (GL_BACK);
-	glReadBuffer  (GL_BACK);
-	GL_EndRendering ();
-}
-
-/*
-===============
-R_Init
-===============
-*/
-void R_Init (void)
-{	
-	extern byte *hunk_base;
-	extern cvar_t gl_finish;
-
-	Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);	
-	Cmd_AddCommand ("envmap", R_Envmap_f);	
-	Cmd_AddCommand ("pointfile", R_ReadPointFile_f);	
-
-	Cvar_RegisterVariable (&r_norefresh);
-	Cvar_RegisterVariable (&r_lightmap);
-	Cvar_RegisterVariable (&r_fullbright);
-	Cvar_RegisterVariable (&r_drawentities);
-	Cvar_RegisterVariable (&r_drawviewmodel);
-	Cvar_RegisterVariable (&r_shadows);
-	Cvar_RegisterVariable (&r_mirroralpha);
-	Cvar_RegisterVariable (&r_wateralpha);
-	Cvar_RegisterVariable (&r_dynamic);
-	Cvar_RegisterVariable (&r_novis);
-	Cvar_RegisterVariable (&r_speeds);
-
-	Cvar_RegisterVariable (&gl_finish);
-	Cvar_RegisterVariable (&gl_clear);
-	Cvar_RegisterVariable (&gl_texsort);
-
- 	if (gl_mtexable)
-		Cvar_SetValue ("gl_texsort", 0.0);
-
-	Cvar_RegisterVariable (&gl_cull);
-	Cvar_RegisterVariable (&gl_smoothmodels);
-	Cvar_RegisterVariable (&gl_affinemodels);
-	Cvar_RegisterVariable (&gl_polyblend);
-	Cvar_RegisterVariable (&gl_flashblend);
-	Cvar_RegisterVariable (&gl_playermip);
-	Cvar_RegisterVariable (&gl_nocolors);
-
-	Cvar_RegisterVariable (&gl_keeptjunctions);
-	Cvar_RegisterVariable (&gl_reporttjunctions);
-
-	Cvar_RegisterVariable (&gl_doubleeyes);
-
-	R_InitParticles ();
-	R_InitParticleTexture ();
-
-#ifdef GLTEST
-	Test_Init ();
-#endif
-
-	playertextures = texture_extension_number;
-	texture_extension_number += 16;
-}
-
-/*
-===============
-R_TranslatePlayerSkin
-
-Translates a skin texture by the per-player color lookup
-===============
-*/
-void R_TranslatePlayerSkin (int playernum)
-{
-	int		top, bottom;
-	byte	translate[256];
-	unsigned	translate32[256];
-	int		i, j, s;
-	model_t	*model;
-	aliashdr_t *paliashdr;
-	byte	*original;
-	unsigned	pixels[512*256], *out;
-	unsigned	scaled_width, scaled_height;
-	int			inwidth, inheight;
-	byte		*inrow;
-	unsigned	frac, fracstep;
-	extern	byte		**player_8bit_texels_tbl;
-
-	GL_DisableMultitexture();
-
-	top = cl.scores[playernum].colors & 0xf0;
-	bottom = (cl.scores[playernum].colors &15)<<4;
-
-	for (i=0 ; i<256 ; i++)
-		translate[i] = i;
-
-	for (i=0 ; i<16 ; i++)
-	{
-		if (top < 128)	// the artists made some backwards ranges.  sigh.
-			translate[TOP_RANGE+i] = top+i;
-		else
-			translate[TOP_RANGE+i] = top+15-i;
-				
-		if (bottom < 128)
-			translate[BOTTOM_RANGE+i] = bottom+i;
-		else
-			translate[BOTTOM_RANGE+i] = bottom+15-i;
-	}
-
-	//
-	// locate the original skin pixels
-	//
-	currententity = &cl_entities[1+playernum];
-	model = currententity->model;
-	if (!model)
-		return;		// player doesn't have a model yet
-	if (model->type != mod_alias)
-		return; // only translate skins on alias models
-
-	paliashdr = (aliashdr_t *)Mod_Extradata (model);
-	s = paliashdr->skinwidth * paliashdr->skinheight;
-	if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins) {
-		Con_Printf("(%d): Invalid player skin #%d\n", playernum, currententity->skinnum);
-		original = (byte *)paliashdr + paliashdr->texels[0];
-	} else
-		original = (byte *)paliashdr + paliashdr->texels[currententity->skinnum];
-	if (s & 3)
-		Sys_Error ("R_TranslateSkin: s&3");
-
-	inwidth = paliashdr->skinwidth;
-	inheight = paliashdr->skinheight;
-
-	// because this happens during gameplay, do it fast
-	// instead of sending it through gl_upload 8
-    GL_Bind(playertextures + playernum);
-
-#if 0
-	byte	translated[320*200];
-
-	for (i=0 ; i<s ; i+=4)
-	{
-		translated[i] = translate[original[i]];
-		translated[i+1] = translate[original[i+1]];
-		translated[i+2] = translate[original[i+2]];
-		translated[i+3] = translate[original[i+3]];
-	}
-
-
-	// don't mipmap these, because it takes too long
-	GL_Upload8 (translated, paliashdr->skinwidth, paliashdr->skinheight, false, false, true);
-#else
-	scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;
-	scaled_height = gl_max_size.value < 256 ? gl_max_size.value : 256;
-
-	// allow users to crunch sizes down even more if they want
-	scaled_width >>= (int)gl_playermip.value;
-	scaled_height >>= (int)gl_playermip.value;
-
-	if (VID_Is8bit()) { // 8bit texture upload
-		byte *out2;
-
-		out2 = (byte *)pixels;
-		memset(pixels, 0, sizeof(pixels));
-		fracstep = inwidth*0x10000/scaled_width;
-		for (i=0 ; i<scaled_height ; i++, out2 += scaled_width)
-		{
-			inrow = original + inwidth*(i*inheight/scaled_height);
-			frac = fracstep >> 1;
-			for (j=0 ; j<scaled_width ; j+=4)
-			{
-				out2[j] = translate[inrow[frac>>16]];
-				frac += fracstep;
-				out2[j+1] = translate[inrow[frac>>16]];
-				frac += fracstep;
-				out2[j+2] = translate[inrow[frac>>16]];
-				frac += fracstep;
-				out2[j+3] = translate[inrow[frac>>16]];
-				frac += fracstep;
-			}
-		}
-
-		GL_Upload8_EXT ((byte *)pixels, scaled_width, scaled_height, false, false);
-		return;
-	}
-
-	for (i=0 ; i<256 ; i++)
-		translate32[i] = d_8to24table[translate[i]];
-
-	out = pixels;
-	fracstep = inwidth*0x10000/scaled_width;
-	for (i=0 ; i<scaled_height ; i++, out += scaled_width)
-	{
-		inrow = original + inwidth*(i*inheight/scaled_height);
-		frac = fracstep >> 1;
-		for (j=0 ; j<scaled_width ; j+=4)
-		{
-			out[j] = translate32[inrow[frac>>16]];
-			frac += fracstep;
-			out[j+1] = translate32[inrow[frac>>16]];
-			frac += fracstep;
-			out[j+2] = translate32[inrow[frac>>16]];
-			frac += fracstep;
-			out[j+3] = translate32[inrow[frac>>16]];
-			frac += fracstep;
-		}
-	}
-	glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-
-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-#endif
-
-}
-
-
-/*
-===============
-R_NewMap
-===============
-*/
-void R_NewMap (void)
-{
-	int		i;
-	
-	for (i=0 ; i<256 ; i++)
-		d_lightstylevalue[i] = 264;		// normal light value
-
-	memset (&r_worldentity, 0, sizeof(r_worldentity));
-	r_worldentity.model = cl.worldmodel;
-
-// clear out efrags in case the level hasn't been reloaded
-// FIXME: is this one short?
-	for (i=0 ; i<cl.worldmodel->numleafs ; i++)
-		cl.worldmodel->leafs[i].efrags = NULL;
-		 	
-	r_viewleaf = NULL;
-	R_ClearParticles ();
-
-	GL_BuildLightmaps ();
-
-	// identify sky texture
-	skytexturenum = -1;
-	mirrortexturenum = -1;
-	for (i=0 ; i<cl.worldmodel->numtextures ; i++)
-	{
-		if (!cl.worldmodel->textures[i])
-			continue;
-		if (!Q_strncmp(cl.worldmodel->textures[i]->name,"sky",3) )
-			skytexturenum = i;
-		if (!Q_strncmp(cl.worldmodel->textures[i]->name,"window02_1",10) )
-			mirrortexturenum = i;
- 		cl.worldmodel->textures[i]->texturechain = NULL;
-	}
-#ifdef QUAKE2
-	R_LoadSkys ();
-#endif
-}
-
-
-/*
-====================
-R_TimeRefresh_f
-
-For program optimization
-====================
-*/
-void R_TimeRefresh_f (void)
-{
-	int			i;
-	float		start, stop, time;
-	int			startangle;
-	vrect_t		vr;
-
-	glDrawBuffer  (GL_FRONT);
-	glFinish ();
-
-	start = Sys_FloatTime ();
-	for (i=0 ; i<128 ; i++)
-	{
-		r_refdef.viewangles[1] = i/128.0*360.0;
-		R_RenderView ();
-	}
-
-	glFinish ();
-	stop = Sys_FloatTime ();
-	time = stop-start;
-	Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
-
-	glDrawBuffer  (GL_BACK);
-	GL_EndRendering ();
-}
-
-void D_FlushCaches (void)
-{
-}
-
-
diff --git a/quake/src/WinQuake/gl_rmisc.cpp b/quake/src/WinQuake/gl_rmisc.cpp
new file mode 100755
index 0000000..0fa92c2
--- /dev/null
+++ b/quake/src/WinQuake/gl_rmisc.cpp
@@ -0,0 +1,480 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// r_misc.c
+
+#include "quakedef.h"
+
+
+
+/*
+==================
+R_InitTextures
+==================
+*/
+void	R_InitTextures (void)
+{
+  int		x,y, m;
+  byte	*dest;
+
+// create a simple checkerboard texture for the default
+  r_notexture_mip = (texture_t*) Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture");
+
+  r_notexture_mip->width = r_notexture_mip->height = 16;
+  r_notexture_mip->offsets[0] = sizeof(texture_t);
+  r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
+  r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
+  r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
+
+  for (m=0 ; m<4 ; m++)
+  {
+    dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
+    for (y=0 ; y< (16>>m) ; y++)
+      for (x=0 ; x< (16>>m) ; x++)
+      {
+        if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
+          *dest++ = 0;
+        else
+          *dest++ = 0xff;
+      }
+  }
+}
+
+byte	dottexture[8][8] =
+{
+  {0,1,1,0,0,0,0,0},
+  {1,1,1,1,0,0,0,0},
+  {1,1,1,1,0,0,0,0},
+  {0,1,1,0,0,0,0,0},
+  {0,0,0,0,0,0,0,0},
+  {0,0,0,0,0,0,0,0},
+  {0,0,0,0,0,0,0,0},
+  {0,0,0,0,0,0,0,0},
+};
+// Initialize particle texture, can be called multiple times.
+void R_InitParticleTexture2 (void)
+{
+  int		x,y;
+  byte	data[8][8][4];
+
+  //
+  // particle texture
+  //
+    GL_Bind(particletexture);
+
+  for (x=0 ; x<8 ; x++)
+  {
+    for (y=0 ; y<8 ; y++)
+    {
+      data[y][x][0] = 255;
+      data[y][x][1] = 255;
+      data[y][x][2] = 255;
+      data[y][x][3] = dottexture[x][y]*255;
+    }
+  }
+  glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR);
+}
+
+void R_InitParticleTexture (void)
+{
+  particletexture = texture_extension_number++;
+  R_InitParticleTexture2();
+}
+
+/*
+===============
+R_Envmap_f
+
+Grab six views for environment mapping tests
+===============
+*/
+void R_Envmap_f (void)
+{
+#ifdef USE_OPENGLES
+  // Not implemented
+#else
+  byte	buffer[256*256*4];
+  char	name[1024];
+
+  glDrawBuffer  (GL_FRONT);
+  glReadBuffer  (GL_FRONT);
+  envmap = true;
+
+  r_refdef.vrect.x = 0;
+  r_refdef.vrect.y = 0;
+  r_refdef.vrect.width = 256;
+  r_refdef.vrect.height = 256;
+
+  r_refdef.viewangles[0] = 0;
+  r_refdef.viewangles[1] = 0;
+  r_refdef.viewangles[2] = 0;
+  GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
+  R_RenderView ();
+  glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+  COM_WriteFile ("env0.rgb", buffer, sizeof(buffer));
+
+  r_refdef.viewangles[1] = 90;
+  GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
+  R_RenderView ();
+  glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+  COM_WriteFile ("env1.rgb", buffer, sizeof(buffer));
+
+  r_refdef.viewangles[1] = 180;
+  GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
+  R_RenderView ();
+  glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+  COM_WriteFile ("env2.rgb", buffer, sizeof(buffer));
+
+  r_refdef.viewangles[1] = 270;
+  GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
+  R_RenderView ();
+  glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+  COM_WriteFile ("env3.rgb", buffer, sizeof(buffer));
+
+  r_refdef.viewangles[0] = -90;
+  r_refdef.viewangles[1] = 0;
+  GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
+  R_RenderView ();
+  glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+  COM_WriteFile ("env4.rgb", buffer, sizeof(buffer));
+
+  r_refdef.viewangles[0] = 90;
+  r_refdef.viewangles[1] = 0;
+  GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
+  R_RenderView ();
+  glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+  COM_WriteFile ("env5.rgb", buffer, sizeof(buffer));
+
+  envmap = false;
+  glDrawBuffer  (GL_BACK);
+  glReadBuffer  (GL_BACK);
+  GL_EndRendering ();
+#endif
+}
+
+/*
+===============
+R_Init
+===============
+*/
+void R_Init (void)
+{
+  extern byte *hunk_base;
+  extern cvar_t gl_finish;
+
+  Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
+  Cmd_AddCommand ("envmap", R_Envmap_f);
+  Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
+
+  Cvar_RegisterVariable (&r_norefresh);
+  Cvar_RegisterVariable (&r_lightmap);
+  Cvar_RegisterVariable (&r_fullbright);
+  Cvar_RegisterVariable (&r_drawentities);
+  Cvar_RegisterVariable (&r_drawviewmodel);
+  Cvar_RegisterVariable (&r_shadows);
+  Cvar_RegisterVariable (&r_mirroralpha);
+  Cvar_RegisterVariable (&r_wateralpha);
+  Cvar_RegisterVariable (&r_dynamic);
+  Cvar_RegisterVariable (&r_novis);
+  Cvar_RegisterVariable (&r_speeds);
+
+  Cvar_RegisterVariable (&gl_finish);
+  Cvar_RegisterVariable (&gl_clear);
+  Cvar_RegisterVariable (&gl_texsort);
+
+   if (gl_mtexable)
+    Cvar_SetValue ("gl_texsort", 0.0);
+
+  Cvar_RegisterVariable (&gl_cull);
+  Cvar_RegisterVariable (&gl_smoothmodels);
+  Cvar_RegisterVariable (&gl_affinemodels);
+  Cvar_RegisterVariable (&gl_polyblend);
+  Cvar_RegisterVariable (&gl_flashblend);
+  Cvar_RegisterVariable (&gl_playermip);
+  Cvar_RegisterVariable (&gl_nocolors);
+
+  Cvar_RegisterVariable (&gl_keeptjunctions);
+  Cvar_RegisterVariable (&gl_reporttjunctions);
+
+  Cvar_RegisterVariable (&gl_doubleeyes);
+
+  R_InitParticles ();
+  R_InitParticleTexture ();
+
+#ifdef GLTEST
+  Test_Init ();
+#endif
+
+  playertextures = texture_extension_number;
+  texture_extension_number += 16;
+}
+
+/*
+===============
+R_TranslatePlayerSkin
+
+Translates a skin texture by the per-player color lookup
+===============
+*/
+void R_TranslatePlayerSkin (int playernum)
+{
+  int		top, bottom;
+  byte	translate[256];
+  unsigned	translate32[256];
+  int		i, j, s;
+  model_t	*model;
+  aliashdr_t *paliashdr;
+  byte	*original;
+  unsigned*	pixels;
+  unsigned    *out;
+  unsigned	scaled_width, scaled_height;
+  int			inwidth, inheight;
+  byte		*inrow;
+  unsigned	frac, fracstep;
+  extern	byte		**player_8bit_texels_tbl;
+
+  GL_DisableMultitexture();
+
+  top = cl.scores[playernum].colors & 0xf0;
+  bottom = (cl.scores[playernum].colors &15)<<4;
+
+  for (i=0 ; i<256 ; i++)
+    translate[i] = i;
+
+  for (i=0 ; i<16 ; i++)
+  {
+    if (top < 128)	// the artists made some backwards ranges.  sigh.
+      translate[TOP_RANGE+i] = top+i;
+    else
+      translate[TOP_RANGE+i] = top+15-i;
+
+    if (bottom < 128)
+      translate[BOTTOM_RANGE+i] = bottom+i;
+    else
+      translate[BOTTOM_RANGE+i] = bottom+15-i;
+  }
+
+  //
+  // locate the original skin pixels
+  //
+  currententity = &cl_entities[1+playernum];
+  model = currententity->model;
+  if (!model)
+    return;		// player doesn't have a model yet
+  if (model->type != mod_alias)
+    return; // only translate skins on alias models
+
+  paliashdr = (aliashdr_t *)Mod_Extradata (model);
+  s = paliashdr->skinwidth * paliashdr->skinheight;
+  if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins) {
+    Con_Printf("(%d): Invalid player skin #%d\n", playernum, currententity->skinnum);
+    original = (byte *)paliashdr + paliashdr->texels[0];
+  } else
+    original = (byte *)paliashdr + paliashdr->texels[currententity->skinnum];
+  if (s & 3)
+    Sys_Error ("R_TranslateSkin: s&3");
+
+  inwidth = paliashdr->skinwidth;
+  inheight = paliashdr->skinheight;
+
+  // because this happens during gameplay, do it fast
+  // instead of sending it through gl_upload 8
+    GL_Bind(playertextures + playernum);
+
+#if 0
+  byte	translated[320*200];
+
+  for (i=0 ; i<s ; i+=4)
+  {
+    translated[i] = translate[original[i]];
+    translated[i+1] = translate[original[i+1]];
+    translated[i+2] = translate[original[i+2]];
+    translated[i+3] = translate[original[i+3]];
+  }
+
+
+  // don't mipmap these, because it takes too long
+  GL_Upload8 (translated, paliashdr->skinwidth, paliashdr->skinheight, false, false, true);
+#else
+  scaled_width = (unsigned int) (gl_max_size.value < 512 ? gl_max_size.value : 512);
+  scaled_height = (unsigned int) (gl_max_size.value < 256 ? gl_max_size.value : 256);
+
+  // allow users to crunch sizes down even more if they want
+  scaled_width >>= (int)gl_playermip.value;
+  scaled_height >>= (int)gl_playermip.value;
+
+#define PIXEL_COUNT (512*256)
+#define PIXELS_SIZE (PIXEL_COUNT * sizeof(unsigned))
+
+  pixels = (unsigned*) malloc(PIXELS_SIZE);
+  if(!pixels)
+  {
+    Sys_Error("Out of memory.");
+  }
+
+  if (VID_Is8bit()) { // 8bit texture upload
+    byte *out2;
+
+    out2 = (byte *)pixels;
+    memset(pixels, 0, PIXELS_SIZE);
+    fracstep = inwidth*0x10000/scaled_width;
+    for (i=0 ; i< (int) scaled_height ; i++, out2 += scaled_width)
+    {
+      inrow = original + inwidth*(i*inheight/scaled_height);
+      frac = fracstep >> 1;
+      for (j=0 ; j< (int) scaled_width ; j+=4)
+      {
+        out2[j] = translate[inrow[frac>>16]];
+        frac += fracstep;
+        out2[j+1] = translate[inrow[frac>>16]];
+        frac += fracstep;
+        out2[j+2] = translate[inrow[frac>>16]];
+        frac += fracstep;
+        out2[j+3] = translate[inrow[frac>>16]];
+        frac += fracstep;
+      }
+    }
+
+    GL_Upload8_EXT ((byte *)pixels, scaled_width, scaled_height, false, false);
+  }
+  else
+  {
+
+    for (i=0 ; i<256 ; i++)
+      translate32[i] = d_8to24table[translate[i]];
+
+    out = pixels;
+    fracstep = inwidth*0x10000/scaled_width;
+    for (i=0 ; i< (int) scaled_height ; i++, out += scaled_width)
+    {
+      inrow = original + inwidth*(i*inheight/scaled_height);
+      frac = fracstep >> 1;
+      for (j=0 ; j< (int) scaled_width ; j+=4)
+      {
+        out[j] = translate32[inrow[frac>>16]];
+        frac += fracstep;
+        out[j+1] = translate32[inrow[frac>>16]];
+        frac += fracstep;
+        out[j+2] = translate32[inrow[frac>>16]];
+        frac += fracstep;
+        out[j+3] = translate32[inrow[frac>>16]];
+        frac += fracstep;
+      }
+    }
+    glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  }
+#endif
+  free(pixels);
+}
+
+
+/*
+===============
+R_NewMap
+===============
+*/
+void R_NewMap (void)
+{
+  int		i;
+
+  for (i=0 ; i<256 ; i++)
+    d_lightstylevalue[i] = 264;		// normal light value
+
+  memset (&r_worldentity, 0, sizeof(r_worldentity));
+  r_worldentity.model = cl.worldmodel;
+
+// clear out efrags in case the level hasn't been reloaded
+// FIXME: is this one short?
+  for (i=0 ; i<cl.worldmodel->numleafs ; i++)
+    cl.worldmodel->leafs[i].efrags = NULL;
+
+  r_viewleaf = NULL;
+  R_ClearParticles ();
+
+  GL_BuildLightmaps ();
+
+  // identify sky texture
+  skytexturenum = -1;
+  mirrortexturenum = -1;
+  for (i=0 ; i<cl.worldmodel->numtextures ; i++)
+  {
+    if (!cl.worldmodel->textures[i])
+      continue;
+    if (!Q_strncmp(cl.worldmodel->textures[i]->name,"sky",3) )
+      skytexturenum = i;
+    if (!Q_strncmp(cl.worldmodel->textures[i]->name,"window02_1",10) )
+      mirrortexturenum = i;
+     cl.worldmodel->textures[i]->texturechain = NULL;
+  }
+#ifdef QUAKE2
+  R_LoadSkys ();
+#endif
+}
+
+
+/*
+====================
+R_TimeRefresh_f
+
+For program optimization
+====================
+*/
+void R_TimeRefresh_f (void)
+{
+#ifdef USE_OPENGLES
+  // Not implemented
+  Con_Printf("TimeRefresh not implemented.\n");
+#else
+  int			i;
+  float		start, stop, time;
+  int			startangle;
+  vrect_t		vr;
+
+  glDrawBuffer  (GL_FRONT);
+  glFinish ();
+
+  start = Sys_FloatTime ();
+  for (i=0 ; i<128 ; i++)
+  {
+    r_refdef.viewangles[1] = i/128.0*360.0;
+    R_RenderView ();
+  }
+
+  glFinish ();
+  stop = Sys_FloatTime ();
+  time = stop-start;
+  Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
+
+  glDrawBuffer  (GL_BACK);
+  GL_EndRendering ();
+#endif
+}
+
+void D_FlushCaches (void)
+{
+}
diff --git a/quake/src/WinQuake/gl_rsurf.c b/quake/src/WinQuake/gl_rsurf.c
deleted file mode 100644
index 572228f..0000000
--- a/quake/src/WinQuake/gl_rsurf.c
+++ /dev/null
@@ -1,1694 +0,0 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// r_surf.c: surface-related refresh code
-
-#include "quakedef.h"
-
-int			skytexturenum;
-
-#ifndef GL_RGBA4
-#define	GL_RGBA4	0
-#endif
-
-
-int		lightmap_bytes;		// 1, 2, or 4
-
-int		lightmap_textures;
-
-unsigned		blocklights[18*18];
-
-#define	BLOCK_WIDTH		128
-#define	BLOCK_HEIGHT	128
-
-#define	MAX_LIGHTMAPS	64
-int			active_lightmaps;
-
-typedef struct glRect_s {
-	unsigned char l,t,w,h;
-} glRect_t;
-
-glpoly_t	*lightmap_polys[MAX_LIGHTMAPS];
-qboolean	lightmap_modified[MAX_LIGHTMAPS];
-glRect_t	lightmap_rectchange[MAX_LIGHTMAPS];
-
-int			allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
-
-// the lightmap texture data needs to be kept in
-// main memory so texsubimage can update properly
-byte		lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT];
-
-// For gl_texsort 0
-msurface_t  *skychain = NULL;
-msurface_t  *waterchain = NULL;
-
-void R_RenderDynamicLightmaps (msurface_t *fa);
-
-/*
-===============
-R_AddDynamicLights
-===============
-*/
-void R_AddDynamicLights (msurface_t *surf)
-{
-	int			lnum;
-	int			sd, td;
-	float		dist, rad, minlight;
-	vec3_t		impact, local;
-	int			s, t;
-	int			i;
-	int			smax, tmax;
-	mtexinfo_t	*tex;
-
-	smax = (surf->extents[0]>>4)+1;
-	tmax = (surf->extents[1]>>4)+1;
-	tex = surf->texinfo;
-
-	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
-	{
-		if ( !(surf->dlightbits & (1<<lnum) ) )
-			continue;		// not lit by this light
-
-		rad = cl_dlights[lnum].radius;
-		dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -
-				surf->plane->dist;
-		rad -= fabs(dist);
-		minlight = cl_dlights[lnum].minlight;
-		if (rad < minlight)
-			continue;
-		minlight = rad - minlight;
-
-		for (i=0 ; i<3 ; i++)
-		{
-			impact[i] = cl_dlights[lnum].origin[i] -
-					surf->plane->normal[i]*dist;
-		}
-
-		local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
-		local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
-
-		local[0] -= surf->texturemins[0];
-		local[1] -= surf->texturemins[1];
-		
-		for (t = 0 ; t<tmax ; t++)
-		{
-			td = local[1] - t*16;
-			if (td < 0)
-				td = -td;
-			for (s=0 ; s<smax ; s++)
-			{
-				sd = local[0] - s*16;
-				if (sd < 0)
-					sd = -sd;
-				if (sd > td)
-					dist = sd + (td>>1);
-				else
-					dist = td + (sd>>1);
-				if (dist < minlight)
-					blocklights[t*smax + s] += (rad - dist)*256;
-			}
-		}
-	}
-}
-
-
-/*
-===============
-R_BuildLightMap
-
-Combine and scale multiple lightmaps into the 8.8 format in blocklights
-===============
-*/
-void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
-{
-	int			smax, tmax;
-	int			t;
-	int			i, j, size;
-	byte		*lightmap;
-	unsigned	scale;
-	int			maps;
-	int			lightadj[4];
-	unsigned	*bl;
-
-	surf->cached_dlight = (surf->dlightframe == r_framecount);
-
-	smax = (surf->extents[0]>>4)+1;
-	tmax = (surf->extents[1]>>4)+1;
-	size = smax*tmax;
-	lightmap = surf->samples;
-
-// set to full bright if no light data
-	if (r_fullbright.value || !cl.worldmodel->lightdata)
-	{
-		for (i=0 ; i<size ; i++)
-			blocklights[i] = 255*256;
-		goto store;
-	}
-
-// clear to no light
-	for (i=0 ; i<size ; i++)
-		blocklights[i] = 0;
-
-// add all the lightmaps
-	if (lightmap)
-		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
-			 maps++)
-		{
-			scale = d_lightstylevalue[surf->styles[maps]];
-			surf->cached_light[maps] = scale;	// 8.8 fraction
-			for (i=0 ; i<size ; i++)
-				blocklights[i] += lightmap[i] * scale;
-			lightmap += size;	// skip to next lightmap
-		}
-
-// add all the dynamic lights
-	if (surf->dlightframe == r_framecount)
-		R_AddDynamicLights (surf);
-
-// bound, invert, and shift
-store:
-	switch (gl_lightmap_format)
-	{
-	case GL_RGBA:
-		stride -= (smax<<2);
-		bl = blocklights;
-		for (i=0 ; i<tmax ; i++, dest += stride)
-		{
-			for (j=0 ; j<smax ; j++)
-			{
-				t = *bl++;
-				t >>= 7;
-				if (t > 255)
-					t = 255;
-				dest[3] = 255-t;
-				dest += 4;
-			}
-		}
-		break;
-	case GL_ALPHA:
-	case GL_LUMINANCE:
-	case GL_INTENSITY:
-		bl = blocklights;
-		for (i=0 ; i<tmax ; i++, dest += stride)
-		{
-			for (j=0 ; j<smax ; j++)
-			{
-				t = *bl++;
-				t >>= 7;
-				if (t > 255)
-					t = 255;
-				dest[j] = 255-t;
-			}
-		}
-		break;
-	default:
-		Sys_Error ("Bad lightmap format");
-	}
-}
-
-
-/*
-===============
-R_TextureAnimation
-
-Returns the proper texture for a given time and base texture
-===============
-*/
-texture_t *R_TextureAnimation (texture_t *base)
-{
-	int		reletive;
-	int		count;
-
-	if (currententity->frame)
-	{
-		if (base->alternate_anims)
-			base = base->alternate_anims;
-	}
-	
-	if (!base->anim_total)
-		return base;
-
-	reletive = (int)(cl.time*10) % base->anim_total;
-
-	count = 0;	
-	while (base->anim_min > reletive || base->anim_max <= reletive)
-	{
-		base = base->anim_next;
-		if (!base)
-			Sys_Error ("R_TextureAnimation: broken cycle");
-		if (++count > 100)
-			Sys_Error ("R_TextureAnimation: infinite cycle");
-	}
-
-	return base;
-}
-
-
-/*
-=============================================================
-
-	BRUSH MODELS
-
-=============================================================
-*/
-
-
-extern	int		solidskytexture;
-extern	int		alphaskytexture;
-extern	float	speedscale;		// for top sky and bottom sky
-
-void DrawGLWaterPoly (glpoly_t *p);
-void DrawGLWaterPolyLightmap (glpoly_t *p);
-
-lpMTexFUNC qglMTexCoord2fSGIS = NULL;
-lpSelTexFUNC qglSelectTextureSGIS = NULL;
-
-qboolean mtexenabled = false;
-
-void GL_SelectTexture (GLenum target);
-
-void GL_DisableMultitexture(void) 
-{
-	if (mtexenabled) {
-		glDisable(GL_TEXTURE_2D);
-		GL_SelectTexture(TEXTURE0_SGIS);
-		mtexenabled = false;
-	}
-}
-
-void GL_EnableMultitexture(void) 
-{
-	if (gl_mtexable) {
-		GL_SelectTexture(TEXTURE1_SGIS);
-		glEnable(GL_TEXTURE_2D);
-		mtexenabled = true;
-	}
-}
-
-#if 0
-/*
-================
-R_DrawSequentialPoly
-
-Systems that have fast state and texture changes can
-just do everything as it passes with no need to sort
-================
-*/
-void R_DrawSequentialPoly (msurface_t *s)
-{
-	glpoly_t	*p;
-	float		*v;
-	int			i;
-	texture_t	*t;
-
-	//
-	// normal lightmaped poly
-	//
-	if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
-	{
-		p = s->polys;
-
-		t = R_TextureAnimation (s->texinfo->texture);
-		GL_Bind (t->gl_texturenum);
-		glBegin (GL_POLYGON);
-		v = p->verts[0];
-		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-		{
-			glTexCoord2f (v[3], v[4]);
-			glVertex3fv (v);
-		}
-		glEnd ();
-
-		GL_Bind (lightmap_textures + s->lightmaptexturenum);
-		glEnable (GL_BLEND);
-		glBegin (GL_POLYGON);
-		v = p->verts[0];
-		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-		{
-			glTexCoord2f (v[5], v[6]);
-			glVertex3fv (v);
-		}
-		glEnd ();
-
-		glDisable (GL_BLEND);
-
-		return;
-	}
-
-	//
-	// subdivided water surface warp
-	//
-	if (s->flags & SURF_DRAWTURB)
-	{
-		GL_Bind (s->texinfo->texture->gl_texturenum);
-		EmitWaterPolys (s);
-		return;
-	}
-
-	//
-	// subdivided sky warp
-	//
-	if (s->flags & SURF_DRAWSKY)
-	{
-		GL_Bind (solidskytexture);
-		speedscale = realtime*8;
-		speedscale -= (int)speedscale;
-
-		EmitSkyPolys (s);
-
-		glEnable (GL_BLEND);
-		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		GL_Bind (alphaskytexture);
-		speedscale = realtime*16;
-		speedscale -= (int)speedscale;
-		EmitSkyPolys (s);
-		if (gl_lightmap_format == GL_LUMINANCE)
-			glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
-
-		glDisable (GL_BLEND);
-	}
-
-	//
-	// underwater warped with lightmap
-	//
-	p = s->polys;
-
-	t = R_TextureAnimation (s->texinfo->texture);
-	GL_Bind (t->gl_texturenum);
-	DrawGLWaterPoly (p);
-
-	GL_Bind (lightmap_textures + s->lightmaptexturenum);
-	glEnable (GL_BLEND);
-	DrawGLWaterPolyLightmap (p);
-	glDisable (GL_BLEND);
-}
-#else
-/*
-================
-R_DrawSequentialPoly
-
-Systems that have fast state and texture changes can
-just do everything as it passes with no need to sort
-================
-*/
-void R_DrawSequentialPoly (msurface_t *s)
-{
-	glpoly_t	*p;
-	float		*v;
-	int			i;
-	texture_t	*t;
-	vec3_t		nv, dir;
-	float		ss, ss2, length;
-	float		s1, t1;
-	glRect_t	*theRect;
-
-	//
-	// normal lightmaped poly
-	//
-
-	if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
-	{
-		R_RenderDynamicLightmaps (s);
-		if (gl_mtexable) {
-			p = s->polys;
-
-			t = R_TextureAnimation (s->texinfo->texture);
-			// Binds world to texture env 0
-			GL_SelectTexture(TEXTURE0_SGIS);
-			GL_Bind (t->gl_texturenum);
-			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-			// Binds lightmap to texenv 1
-			GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
-			GL_Bind (lightmap_textures + s->lightmaptexturenum);
-			i = s->lightmaptexturenum;
-			if (lightmap_modified[i])
-			{
-				lightmap_modified[i] = false;
-				theRect = &lightmap_rectchange[i];
-				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
-					BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
-					lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
-				theRect->l = BLOCK_WIDTH;
-				theRect->t = BLOCK_HEIGHT;
-				theRect->h = 0;
-				theRect->w = 0;
-			}
-			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
-			glBegin(GL_POLYGON);
-			v = p->verts[0];
-			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-			{
-				qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
-				qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
-				glVertex3fv (v);
-			}
-			glEnd ();
-			return;
-		} else {
-			p = s->polys;
-
-			t = R_TextureAnimation (s->texinfo->texture);
-			GL_Bind (t->gl_texturenum);
-			glBegin (GL_POLYGON);
-			v = p->verts[0];
-			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-			{
-				glTexCoord2f (v[3], v[4]);
-				glVertex3fv (v);
-			}
-			glEnd ();
-
-			GL_Bind (lightmap_textures + s->lightmaptexturenum);
-			glEnable (GL_BLEND);
-			glBegin (GL_POLYGON);
-			v = p->verts[0];
-			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-			{
-				glTexCoord2f (v[5], v[6]);
-				glVertex3fv (v);
-			}
-			glEnd ();
-
-			glDisable (GL_BLEND);
-		}
-
-		return;
-	}
-
-	//
-	// subdivided water surface warp
-	//
-
-	if (s->flags & SURF_DRAWTURB)
-	{
-		GL_DisableMultitexture();
-		GL_Bind (s->texinfo->texture->gl_texturenum);
-		EmitWaterPolys (s);
-		return;
-	}
-
-	//
-	// subdivided sky warp
-	//
-	if (s->flags & SURF_DRAWSKY)
-	{
-		GL_DisableMultitexture();
-		GL_Bind (solidskytexture);
-		speedscale = realtime*8;
-		speedscale -= (int)speedscale & ~127;
-
-		EmitSkyPolys (s);
-
-		glEnable (GL_BLEND);
-		GL_Bind (alphaskytexture);
-		speedscale = realtime*16;
-		speedscale -= (int)speedscale & ~127;
-		EmitSkyPolys (s);
-
-		glDisable (GL_BLEND);
-		return;
-	}
-
-	//
-	// underwater warped with lightmap
-	//
-	R_RenderDynamicLightmaps (s);
-	if (gl_mtexable) {
-		p = s->polys;
-
-		t = R_TextureAnimation (s->texinfo->texture);
-		GL_SelectTexture(TEXTURE0_SGIS);
-		GL_Bind (t->gl_texturenum);
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		GL_EnableMultitexture();
-		GL_Bind (lightmap_textures + s->lightmaptexturenum);
-		i = s->lightmaptexturenum;
-		if (lightmap_modified[i])
-		{
-			lightmap_modified[i] = false;
-			theRect = &lightmap_rectchange[i];
-			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
-				BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
-				lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
-			theRect->l = BLOCK_WIDTH;
-			theRect->t = BLOCK_HEIGHT;
-			theRect->h = 0;
-			theRect->w = 0;
-		}
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
-		glBegin (GL_TRIANGLE_FAN);
-		v = p->verts[0];
-		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-		{
-			qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
-			qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
-
-			nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
-			nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
-			nv[2] = v[2];
-
-			glVertex3fv (nv);
-		}
-		glEnd ();
-
-	} else {
-		p = s->polys;
-
-		t = R_TextureAnimation (s->texinfo->texture);
-		GL_Bind (t->gl_texturenum);
-		DrawGLWaterPoly (p);
-
-		GL_Bind (lightmap_textures + s->lightmaptexturenum);
-		glEnable (GL_BLEND);
-		DrawGLWaterPolyLightmap (p);
-		glDisable (GL_BLEND);
-	}
-}
-#endif
-
-
-/*
-================
-DrawGLWaterPoly
-
-Warp the vertex coordinates
-================
-*/
-void DrawGLWaterPoly (glpoly_t *p)
-{
-	int		i;
-	float	*v;
-	float	s, t, os, ot;
-	vec3_t	nv;
-
-	GL_DisableMultitexture();
-
-	glBegin (GL_TRIANGLE_FAN);
-	v = p->verts[0];
-	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-	{
-		glTexCoord2f (v[3], v[4]);
-
-		nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
-		nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
-		nv[2] = v[2];
-
-		glVertex3fv (nv);
-	}
-	glEnd ();
-}
-
-void DrawGLWaterPolyLightmap (glpoly_t *p)
-{
-	int		i;
-	float	*v;
-	float	s, t, os, ot;
-	vec3_t	nv;
-
-	GL_DisableMultitexture();
-
-	glBegin (GL_TRIANGLE_FAN);
-	v = p->verts[0];
-	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-	{
-		glTexCoord2f (v[5], v[6]);
-
-		nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
-		nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
-		nv[2] = v[2];
-
-		glVertex3fv (nv);
-	}
-	glEnd ();
-}
-
-/*
-================
-DrawGLPoly
-================
-*/
-void DrawGLPoly (glpoly_t *p)
-{
-	int		i;
-	float	*v;
-
-	glBegin (GL_POLYGON);
-	v = p->verts[0];
-	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
-	{
-		glTexCoord2f (v[3], v[4]);
-		glVertex3fv (v);
-	}
-	glEnd ();
-}
-
-
-/*
-================
-R_BlendLightmaps
-================
-*/
-void R_BlendLightmaps (void)
-{
-	int			i, j;
-	glpoly_t	*p;
-	float		*v;
-	glRect_t	*theRect;
-
-	if (r_fullbright.value)
-		return;
-	if (!gl_texsort.value)
-		return;
-
-	glDepthMask (0);		// don't bother writing Z
-
-	if (gl_lightmap_format == GL_LUMINANCE)
-		glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
-	else if (gl_lightmap_format == GL_INTENSITY)
-	{
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-		glColor4f (0,0,0,1);
-		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	}
-
-	if (!r_lightmap.value)
-	{
-		glEnable (GL_BLEND);
-	}
-
-	for (i=0 ; i<MAX_LIGHTMAPS ; i++)
-	{
-		p = lightmap_polys[i];
-		if (!p)
-			continue;
-		GL_Bind(lightmap_textures+i);
-		if (lightmap_modified[i])
-		{
-			lightmap_modified[i] = false;
-			theRect = &lightmap_rectchange[i];
-//			glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
-//			, BLOCK_WIDTH, BLOCK_HEIGHT, 0, 
-//			gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
-//			glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
-//				, BLOCK_WIDTH, theRect->h, 0, 
-//				gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+(i*BLOCK_HEIGHT+theRect->t)*BLOCK_WIDTH*lightmap_bytes);
-			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
-				BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
-				lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
-			theRect->l = BLOCK_WIDTH;
-			theRect->t = BLOCK_HEIGHT;
-			theRect->h = 0;
-			theRect->w = 0;
-		}
-		for ( ; p ; p=p->chain)
-		{
-			if (p->flags & SURF_UNDERWATER)
-				DrawGLWaterPolyLightmap (p);
-			else
-			{
-				glBegin (GL_POLYGON);
-				v = p->verts[0];
-				for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
-				{
-					glTexCoord2f (v[5], v[6]);
-					glVertex3fv (v);
-				}
-				glEnd ();
-			}
-		}
-	}
-
-	glDisable (GL_BLEND);
-	if (gl_lightmap_format == GL_LUMINANCE)
-		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	else if (gl_lightmap_format == GL_INTENSITY)
-	{
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-		glColor4f (1,1,1,1);
-	}
-
-	glDepthMask (1);		// back to normal Z buffering
-}
-
-/*
-================
-R_RenderBrushPoly
-================
-*/
-void R_RenderBrushPoly (msurface_t *fa)
-{
-	texture_t	*t;
-	byte		*base;
-	int			maps;
-	glRect_t    *theRect;
-	int smax, tmax;
-
-	c_brush_polys++;
-
-	if (fa->flags & SURF_DRAWSKY)
-	{	// warp texture, no lightmaps
-		EmitBothSkyLayers (fa);
-		return;
-	}
-		
-	t = R_TextureAnimation (fa->texinfo->texture);
-	GL_Bind (t->gl_texturenum);
-
-	if (fa->flags & SURF_DRAWTURB)
-	{	// warp texture, no lightmaps
-		EmitWaterPolys (fa);
-		return;
-	}
-
-	if (fa->flags & SURF_UNDERWATER)
-		DrawGLWaterPoly (fa->polys);
-	else
-		DrawGLPoly (fa->polys);
-
-	// add the poly to the proper lightmap chain
-
-	fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
-	lightmap_polys[fa->lightmaptexturenum] = fa->polys;
-
-	// check for lightmap modification
-	for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
-		 maps++)
-		if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
-			goto dynamic;
-
-	if (fa->dlightframe == r_framecount	// dynamic this frame
-		|| fa->cached_dlight)			// dynamic previously
-	{
-dynamic:
-		if (r_dynamic.value)
-		{
-			lightmap_modified[fa->lightmaptexturenum] = true;
-			theRect = &lightmap_rectchange[fa->lightmaptexturenum];
-			if (fa->light_t < theRect->t) {
-				if (theRect->h)
-					theRect->h += theRect->t - fa->light_t;
-				theRect->t = fa->light_t;
-			}
-			if (fa->light_s < theRect->l) {
-				if (theRect->w)
-					theRect->w += theRect->l - fa->light_s;
-				theRect->l = fa->light_s;
-			}
-			smax = (fa->extents[0]>>4)+1;
-			tmax = (fa->extents[1]>>4)+1;
-			if ((theRect->w + theRect->l) < (fa->light_s + smax))
-				theRect->w = (fa->light_s-theRect->l)+smax;
-			if ((theRect->h + theRect->t) < (fa->light_t + tmax))
-				theRect->h = (fa->light_t-theRect->t)+tmax;
-			base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
-			base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
-			R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
-		}
-	}
-}
-
-/*
-================
-R_RenderDynamicLightmaps
-Multitexture
-================
-*/
-void R_RenderDynamicLightmaps (msurface_t *fa)
-{
-	texture_t	*t;
-	byte		*base;
-	int			maps;
-	glRect_t    *theRect;
-	int smax, tmax;
-
-	c_brush_polys++;
-
-	if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) )
-		return;
-		
-	fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
-	lightmap_polys[fa->lightmaptexturenum] = fa->polys;
-
-	// check for lightmap modification
-	for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
-		 maps++)
-		if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
-			goto dynamic;
-
-	if (fa->dlightframe == r_framecount	// dynamic this frame
-		|| fa->cached_dlight)			// dynamic previously
-	{
-dynamic:
-		if (r_dynamic.value)
-		{
-			lightmap_modified[fa->lightmaptexturenum] = true;
-			theRect = &lightmap_rectchange[fa->lightmaptexturenum];
-			if (fa->light_t < theRect->t) {
-				if (theRect->h)
-					theRect->h += theRect->t - fa->light_t;
-				theRect->t = fa->light_t;
-			}
-			if (fa->light_s < theRect->l) {
-				if (theRect->w)
-					theRect->w += theRect->l - fa->light_s;
-				theRect->l = fa->light_s;
-			}
-			smax = (fa->extents[0]>>4)+1;
-			tmax = (fa->extents[1]>>4)+1;
-			if ((theRect->w + theRect->l) < (fa->light_s + smax))
-				theRect->w = (fa->light_s-theRect->l)+smax;
-			if ((theRect->h + theRect->t) < (fa->light_t + tmax))
-				theRect->h = (fa->light_t-theRect->t)+tmax;
-			base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
-			base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
-			R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
-		}
-	}
-}
-
-/*
-================
-R_MirrorChain
-================
-*/
-void R_MirrorChain (msurface_t *s)
-{
-	if (mirror)
-		return;
-	mirror = true;
-	mirror_plane = s->plane;
-}
-
-
-#if 0
-/*
-================
-R_DrawWaterSurfaces
-================
-*/
-void R_DrawWaterSurfaces (void)
-{
-	int			i;
-	msurface_t	*s;
-	texture_t	*t;
-
-	if (r_wateralpha.value == 1.0)
-		return;
-
-	//
-	// go back to the world matrix
-	//
-    glLoadMatrixf (r_world_matrix);
-
-	glEnable (GL_BLEND);
-	glColor4f (1,1,1,r_wateralpha.value);
-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-	for (i=0 ; i<cl.worldmodel->numtextures ; i++)
-	{
-		t = cl.worldmodel->textures[i];
-		if (!t)
-			continue;
-		s = t->texturechain;
-		if (!s)
-			continue;
-		if ( !(s->flags & SURF_DRAWTURB) )
-			continue;
-
-		// set modulate mode explicitly
-		GL_Bind (t->gl_texturenum);
-
-		for ( ; s ; s=s->texturechain)
-			R_RenderBrushPoly (s);
-
-		t->texturechain = NULL;
-	}
-
-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-
-	glColor4f (1,1,1,1);
-	glDisable (GL_BLEND);
-}
-#else
-/*
-================
-R_DrawWaterSurfaces
-================
-*/
-void R_DrawWaterSurfaces (void)
-{
-	int			i;
-	msurface_t	*s;
-	texture_t	*t;
-
-	if (r_wateralpha.value == 1.0 && gl_texsort.value)
-		return;
-
-	//
-	// go back to the world matrix
-	//
-
-    glLoadMatrixf (r_world_matrix);
-
-	if (r_wateralpha.value < 1.0) {
-		glEnable (GL_BLEND);
-		glColor4f (1,1,1,r_wateralpha.value);
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-	}
-
-	if (!gl_texsort.value) {
-		if (!waterchain)
-			return;
-
-		for ( s = waterchain ; s ; s=s->texturechain) {
-			GL_Bind (s->texinfo->texture->gl_texturenum);
-			EmitWaterPolys (s);
-		}
-		
-		waterchain = NULL;
-	} else {
-
-		for (i=0 ; i<cl.worldmodel->numtextures ; i++)
-		{
-			t = cl.worldmodel->textures[i];
-			if (!t)
-				continue;
-			s = t->texturechain;
-			if (!s)
-				continue;
-			if ( !(s->flags & SURF_DRAWTURB ) )
-				continue;
-
-			// set modulate mode explicitly
-			
-			GL_Bind (t->gl_texturenum);
-
-			for ( ; s ; s=s->texturechain)
-				EmitWaterPolys (s);
-			
-			t->texturechain = NULL;
-		}
-
-	}
-
-	if (r_wateralpha.value < 1.0) {
-		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-
-		glColor4f (1,1,1,1);
-		glDisable (GL_BLEND);
-	}
-
-}
-
-#endif
-
-/*
-================
-DrawTextureChains
-================
-*/
-void DrawTextureChains (void)
-{
-	int		i;
-	msurface_t	*s;
-	texture_t	*t;
-
-	if (!gl_texsort.value) {
-		GL_DisableMultitexture();
-
-		if (skychain) {
-			R_DrawSkyChain(skychain);
-			skychain = NULL;
-		}
-
-		return;
-	} 
-
-	for (i=0 ; i<cl.worldmodel->numtextures ; i++)
-	{
-		t = cl.worldmodel->textures[i];
-		if (!t)
-			continue;
-		s = t->texturechain;
-		if (!s)
-			continue;
-		if (i == skytexturenum)
-			R_DrawSkyChain (s);
-		else if (i == mirrortexturenum && r_mirroralpha.value != 1.0)
-		{
-			R_MirrorChain (s);
-			continue;
-		}
-		else
-		{
-			if ((s->flags & SURF_DRAWTURB) && r_wateralpha.value != 1.0)
-				continue;	// draw translucent water later
-			for ( ; s ; s=s->texturechain)
-				R_RenderBrushPoly (s);
-		}
-
-		t->texturechain = NULL;
-	}
-}
-
-/*
-=================
-R_DrawBrushModel
-=================
-*/
-void R_DrawBrushModel (entity_t *e)
-{
-	int			j, k;
-	vec3_t		mins, maxs;
-	int			i, numsurfaces;
-	msurface_t	*psurf;
-	float		dot;
-	mplane_t	*pplane;
-	model_t		*clmodel;
-	qboolean	rotated;
-
-	currententity = e;
-	currenttexture = -1;
-
-	clmodel = e->model;
-
-	if (e->angles[0] || e->angles[1] || e->angles[2])
-	{
-		rotated = true;
-		for (i=0 ; i<3 ; i++)
-		{
-			mins[i] = e->origin[i] - clmodel->radius;
-			maxs[i] = e->origin[i] + clmodel->radius;
-		}
-	}
-	else
-	{
-		rotated = false;
-		VectorAdd (e->origin, clmodel->mins, mins);
-		VectorAdd (e->origin, clmodel->maxs, maxs);
-	}
-
-	if (R_CullBox (mins, maxs))
-		return;
-
-	glColor3f (1,1,1);
-	memset (lightmap_polys, 0, sizeof(lightmap_polys));
-
-	VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
-	if (rotated)
-	{
-		vec3_t	temp;
-		vec3_t	forward, right, up;
-
-		VectorCopy (modelorg, temp);
-		AngleVectors (e->angles, forward, right, up);
-		modelorg[0] = DotProduct (temp, forward);
-		modelorg[1] = -DotProduct (temp, right);
-		modelorg[2] = DotProduct (temp, up);
-	}
-
-	psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
-
-// calculate dynamic lighting for bmodel if it's not an
-// instanced model
-	if (clmodel->firstmodelsurface != 0 && !gl_flashblend.value)
-	{
-		for (k=0 ; k<MAX_DLIGHTS ; k++)
-		{
-			if ((cl_dlights[k].die < cl.time) ||
-				(!cl_dlights[k].radius))
-				continue;
-
-			R_MarkLights (&cl_dlights[k], 1<<k,
-				clmodel->nodes + clmodel->hulls[0].firstclipnode);
-		}
-	}
-
-    glPushMatrix ();
-e->angles[0] = -e->angles[0];	// stupid quake bug
-	R_RotateForEntity (e);
-e->angles[0] = -e->angles[0];	// stupid quake bug
-
-	//
-	// draw texture
-	//
-	for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
-	{
-	// find which side of the node we are on
-		pplane = psurf->plane;
-
-		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
-
-	// draw the polygon
-		if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
-			(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
-		{
-			if (gl_texsort.value)
-				R_RenderBrushPoly (psurf);
-			else
-				R_DrawSequentialPoly (psurf);
-		}
-	}
-
-	R_BlendLightmaps ();
-
-	glPopMatrix ();
-}
-
-/*
-=============================================================
-
-	WORLD MODEL
-
-=============================================================
-*/
-
-/*
-================
-R_RecursiveWorldNode
-================
-*/
-void R_RecursiveWorldNode (mnode_t *node)
-{
-	int			i, c, side, *pindex;
-	vec3_t		acceptpt, rejectpt;
-	mplane_t	*plane;
-	msurface_t	*surf, **mark;
-	mleaf_t		*pleaf;
-	double		d, dot;
-	vec3_t		mins, maxs;
-
-	if (node->contents == CONTENTS_SOLID)
-		return;		// solid
-
-	if (node->visframe != r_visframecount)
-		return;
-	if (R_CullBox (node->minmaxs, node->minmaxs+3))
-		return;
-	
-// if a leaf node, draw stuff
-	if (node->contents < 0)
-	{
-		pleaf = (mleaf_t *)node;
-
-		mark = pleaf->firstmarksurface;
-		c = pleaf->nummarksurfaces;
-
-		if (c)
-		{
-			do
-			{
-				(*mark)->visframe = r_framecount;
-				mark++;
-			} while (--c);
-		}
-
-	// deal with model fragments in this leaf
-		if (pleaf->efrags)
-			R_StoreEfrags (&pleaf->efrags);
-
-		return;
-	}
-
-// node is just a decision point, so go down the apropriate sides
-
-// find which side of the node we are on
-	plane = node->plane;
-
-	switch (plane->type)
-	{
-	case PLANE_X:
-		dot = modelorg[0] - plane->dist;
-		break;
-	case PLANE_Y:
-		dot = modelorg[1] - plane->dist;
-		break;
-	case PLANE_Z:
-		dot = modelorg[2] - plane->dist;
-		break;
-	default:
-		dot = DotProduct (modelorg, plane->normal) - plane->dist;
-		break;
-	}
-
-	if (dot >= 0)
-		side = 0;
-	else
-		side = 1;
-
-// recurse down the children, front side first
-	R_RecursiveWorldNode (node->children[side]);
-
-// draw stuff
-	c = node->numsurfaces;
-
-	if (c)
-	{
-		surf = cl.worldmodel->surfaces + node->firstsurface;
-
-		if (dot < 0 -BACKFACE_EPSILON)
-			side = SURF_PLANEBACK;
-		else if (dot > BACKFACE_EPSILON)
-			side = 0;
-		{
-			for ( ; c ; c--, surf++)
-			{
-				if (surf->visframe != r_framecount)
-					continue;
-
-				// don't backface underwater surfaces, because they warp
-				if ( !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
-					continue;		// wrong side
-
-				// if sorting by texture, just store it out
-				if (gl_texsort.value)
-				{
-					if (!mirror
-					|| surf->texinfo->texture != cl.worldmodel->textures[mirrortexturenum])
-					{
-						surf->texturechain = surf->texinfo->texture->texturechain;
-						surf->texinfo->texture->texturechain = surf;
-					}
-				} else if (surf->flags & SURF_DRAWSKY) {
-					surf->texturechain = skychain;
-					skychain = surf;
-				} else if (surf->flags & SURF_DRAWTURB) {
-					surf->texturechain = waterchain;
-					waterchain = surf;
-				} else
-					R_DrawSequentialPoly (surf);
-
-			}
-		}
-
-	}
-
-// recurse down the back side
-	R_RecursiveWorldNode (node->children[!side]);
-}
-
-
-
-/*
-=============
-R_DrawWorld
-=============
-*/
-void R_DrawWorld (void)
-{
-	entity_t	ent;
-	int			i;
-
-	memset (&ent, 0, sizeof(ent));
-	ent.model = cl.worldmodel;
-
-	VectorCopy (r_refdef.vieworg, modelorg);
-
-	currententity = &ent;
-	currenttexture = -1;
-
-	glColor3f (1,1,1);
-	memset (lightmap_polys, 0, sizeof(lightmap_polys));
-#ifdef QUAKE2
-	R_ClearSkyBox ();
-#endif
-
-	R_RecursiveWorldNode (cl.worldmodel->nodes);
-
-	DrawTextureChains ();
-
-	R_BlendLightmaps ();
-
-#ifdef QUAKE2
-	R_DrawSkyBox ();
-#endif
-}
-
-
-/*
-===============
-R_MarkLeaves
-===============
-*/
-void R_MarkLeaves (void)
-{
-	byte	*vis;
-	mnode_t	*node;
-	int		i;
-	byte	solid[4096];
-
-	if (r_oldviewleaf == r_viewleaf && !r_novis.value)
-		return;
-	
-	if (mirror)
-		return;
-
-	r_visframecount++;
-	r_oldviewleaf = r_viewleaf;
-
-	if (r_novis.value)
-	{
-		vis = solid;
-		memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);
-	}
-	else
-		vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
-		
-	for (i=0 ; i<cl.worldmodel->numleafs ; i++)
-	{
-		if (vis[i>>3] & (1<<(i&7)))
-		{
-			node = (mnode_t *)&cl.worldmodel->leafs[i+1];
-			do
-			{
-				if (node->visframe == r_visframecount)
-					break;
-				node->visframe = r_visframecount;
-				node = node->parent;
-			} while (node);
-		}
-	}
-}
-
-
-
-/*
-=============================================================================
-
-  LIGHTMAP ALLOCATION
-
-=============================================================================
-*/
-
-// returns a texture number and the position inside it
-int AllocBlock (int w, int h, int *x, int *y)
-{
-	int		i, j;
-	int		best, best2;
-	int		bestx;
-	int		texnum;
-
-	for (texnum=0 ; texnum<MAX_LIGHTMAPS ; texnum++)
-	{
-		best = BLOCK_HEIGHT;
-
-		for (i=0 ; i<BLOCK_WIDTH-w ; i++)
-		{
-			best2 = 0;
-
-			for (j=0 ; j<w ; j++)
-			{
-				if (allocated[texnum][i+j] >= best)
-					break;
-				if (allocated[texnum][i+j] > best2)
-					best2 = allocated[texnum][i+j];
-			}
-			if (j == w)
-			{	// this is a valid spot
-				*x = i;
-				*y = best = best2;
-			}
-		}
-
-		if (best + h > BLOCK_HEIGHT)
-			continue;
-
-		for (i=0 ; i<w ; i++)
-			allocated[texnum][*x + i] = best + h;
-
-		return texnum;
-	}
-
-	Sys_Error ("AllocBlock: full");
-}
-
-
-mvertex_t	*r_pcurrentvertbase;
-model_t		*currentmodel;
-
-int	nColinElim;
-
-/*
-================
-BuildSurfaceDisplayList
-================
-*/
-void BuildSurfaceDisplayList (msurface_t *fa)
-{
-	int			i, lindex, lnumverts, s_axis, t_axis;
-	float		dist, lastdist, lzi, scale, u, v, frac;
-	unsigned	mask;
-	vec3_t		local, transformed;
-	medge_t		*pedges, *r_pedge;
-	mplane_t	*pplane;
-	int			vertpage, newverts, newpage, lastvert;
-	qboolean	visible;
-	float		*vec;
-	float		s, t;
-	glpoly_t	*poly;
-
-// reconstruct the polygon
-	pedges = currentmodel->edges;
-	lnumverts = fa->numedges;
-	vertpage = 0;
-
-	//
-	// draw texture
-	//
-	poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));
-	poly->next = fa->polys;
-	poly->flags = fa->flags;
-	fa->polys = poly;
-	poly->numverts = lnumverts;
-
-	for (i=0 ; i<lnumverts ; i++)
-	{
-		lindex = currentmodel->surfedges[fa->firstedge + i];
-
-		if (lindex > 0)
-		{
-			r_pedge = &pedges[lindex];
-			vec = r_pcurrentvertbase[r_pedge->v[0]].position;
-		}
-		else
-		{
-			r_pedge = &pedges[-lindex];
-			vec = r_pcurrentvertbase[r_pedge->v[1]].position;
-		}
-		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
-		s /= fa->texinfo->texture->width;
-
-		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
-		t /= fa->texinfo->texture->height;
-
-		VectorCopy (vec, poly->verts[i]);
-		poly->verts[i][3] = s;
-		poly->verts[i][4] = t;
-
-		//
-		// lightmap texture coordinates
-		//
-		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
-		s -= fa->texturemins[0];
-		s += fa->light_s*16;
-		s += 8;
-		s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
-
-		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
-		t -= fa->texturemins[1];
-		t += fa->light_t*16;
-		t += 8;
-		t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
-
-		poly->verts[i][5] = s;
-		poly->verts[i][6] = t;
-	}
-
-	//
-	// remove co-linear points - Ed
-	//
-	if (!gl_keeptjunctions.value && !(fa->flags & SURF_UNDERWATER) )
-	{
-		for (i = 0 ; i < lnumverts ; ++i)
-		{
-			vec3_t v1, v2;
-			float *prev, *this, *next;
-			float f;
-
-			prev = poly->verts[(i + lnumverts - 1) % lnumverts];
-			this = poly->verts[i];
-			next = poly->verts[(i + 1) % lnumverts];
-
-			VectorSubtract( this, prev, v1 );
-			VectorNormalize( v1 );
-			VectorSubtract( next, prev, v2 );
-			VectorNormalize( v2 );
-
-			// skip co-linear points
-			#define COLINEAR_EPSILON 0.001
-			if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
-				(fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) && 
-				(fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
-			{
-				int j;
-				for (j = i + 1; j < lnumverts; ++j)
-				{
-					int k;
-					for (k = 0; k < VERTEXSIZE; ++k)
-						poly->verts[j - 1][k] = poly->verts[j][k];
-				}
-				--lnumverts;
-				++nColinElim;
-				// retry next vertex next time, which is now current vertex
-				--i;
-			}
-		}
-	}
-	poly->numverts = lnumverts;
-
-}
-
-/*
-========================
-GL_CreateSurfaceLightmap
-========================
-*/
-void GL_CreateSurfaceLightmap (msurface_t *surf)
-{
-	int		smax, tmax, s, t, l, i;
-	byte	*base;
-
-	if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
-		return;
-
-	smax = (surf->extents[0]>>4)+1;
-	tmax = (surf->extents[1]>>4)+1;
-
-	surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
-	base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
-	base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
-	R_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes);
-}
-
-
-/*
-==================
-GL_BuildLightmaps
-
-Builds the lightmap texture
-with all the surfaces from all brush models
-==================
-*/
-void GL_BuildLightmaps (void)
-{
-	int		i, j;
-	model_t	*m;
-	extern qboolean isPermedia;
-
-	memset (allocated, 0, sizeof(allocated));
-
-	r_framecount = 1;		// no dlightcache
-
-	if (!lightmap_textures)
-	{
-		lightmap_textures = texture_extension_number;
-		texture_extension_number += MAX_LIGHTMAPS;
-	}
-
-	gl_lightmap_format = GL_LUMINANCE;
-	// default differently on the Permedia
-	if (isPermedia)
-		gl_lightmap_format = GL_RGBA;
-
-	if (COM_CheckParm ("-lm_1"))
-		gl_lightmap_format = GL_LUMINANCE;
-	if (COM_CheckParm ("-lm_a"))
-		gl_lightmap_format = GL_ALPHA;
-	if (COM_CheckParm ("-lm_i"))
-		gl_lightmap_format = GL_INTENSITY;
-	if (COM_CheckParm ("-lm_2"))
-		gl_lightmap_format = GL_RGBA4;
-	if (COM_CheckParm ("-lm_4"))
-		gl_lightmap_format = GL_RGBA;
-
-	switch (gl_lightmap_format)
-	{
-	case GL_RGBA:
-		lightmap_bytes = 4;
-		break;
-	case GL_RGBA4:
-		lightmap_bytes = 2;
-		break;
-	case GL_LUMINANCE:
-	case GL_INTENSITY:
-	case GL_ALPHA:
-		lightmap_bytes = 1;
-		break;
-	}
-
-	for (j=1 ; j<MAX_MODELS ; j++)
-	{
-		m = cl.model_precache[j];
-		if (!m)
-			break;
-		if (m->name[0] == '*')
-			continue;
-		r_pcurrentvertbase = m->vertexes;
-		currentmodel = m;
-		for (i=0 ; i<m->numsurfaces ; i++)
-		{
-			GL_CreateSurfaceLightmap (m->surfaces + i);
-			if ( m->surfaces[i].flags & SURF_DRAWTURB )
-				continue;
-#ifndef QUAKE2
-			if ( m->surfaces[i].flags & SURF_DRAWSKY )
-				continue;
-#endif
-			BuildSurfaceDisplayList (m->surfaces + i);
-		}
-	}
-
- 	if (!gl_texsort.value)
- 		GL_SelectTexture(TEXTURE1_SGIS);
-
-	//
-	// upload all lightmaps that were filled
-	//
-	for (i=0 ; i<MAX_LIGHTMAPS ; i++)
-	{
-		if (!allocated[i][0])
-			break;		// no more used
-		lightmap_modified[i] = false;
-		lightmap_rectchange[i].l = BLOCK_WIDTH;
-		lightmap_rectchange[i].t = BLOCK_HEIGHT;
-		lightmap_rectchange[i].w = 0;
-		lightmap_rectchange[i].h = 0;
-		GL_Bind(lightmap_textures + i);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-		glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
-		, BLOCK_WIDTH, BLOCK_HEIGHT, 0, 
-		gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
-	}
-
- 	if (!gl_texsort.value)
- 		GL_SelectTexture(TEXTURE0_SGIS);
-
-}
-
diff --git a/quake/src/WinQuake/gl_rsurf.cpp b/quake/src/WinQuake/gl_rsurf.cpp
new file mode 100755
index 0000000..93526e9
--- /dev/null
+++ b/quake/src/WinQuake/gl_rsurf.cpp
@@ -0,0 +1,1802 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// r_surf.c: surface-related refresh code
+
+#include "quakedef.h"
+
+int			skytexturenum;
+
+#ifndef GL_RGBA4
+#define	GL_RGBA4	0
+#endif
+
+
+int		lightmap_bytes;		// 1, 2, or 4
+
+int		lightmap_textures;
+
+unsigned		blocklights[18*18];
+
+#define	BLOCK_WIDTH		128
+#define	BLOCK_HEIGHT	128
+
+#define	MAX_LIGHTMAPS	64
+int			active_lightmaps;
+
+typedef struct glRect_s {
+  unsigned char l,t,w,h;
+} glRect_t;
+
+glpoly_t	*lightmap_polys[MAX_LIGHTMAPS];
+qboolean	lightmap_modified[MAX_LIGHTMAPS];
+glRect_t	lightmap_rectchange[MAX_LIGHTMAPS];
+
+int			allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
+
+// the lightmap texture data needs to be kept in
+// main memory so texsubimage can update properly
+byte		lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT];
+
+// For gl_texsort 0
+msurface_t  *skychain = NULL;
+msurface_t  *waterchain = NULL;
+
+void R_RenderDynamicLightmaps (msurface_t *fa);
+
+/*
+===============
+R_AddDynamicLights
+===============
+*/
+void R_AddDynamicLights (msurface_t *surf)
+{
+  int			lnum;
+  int			sd, td;
+  float		dist, rad, minlight;
+  vec3_t		impact, local;
+  int			s, t;
+  int			i;
+  int			smax, tmax;
+  mtexinfo_t	*tex;
+
+  smax = (surf->extents[0]>>4)+1;
+  tmax = (surf->extents[1]>>4)+1;
+  tex = surf->texinfo;
+
+  for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
+  {
+    if ( !(surf->dlightbits & (1<<lnum) ) )
+      continue;		// not lit by this light
+
+    rad = cl_dlights[lnum].radius;
+    dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -
+        surf->plane->dist;
+    rad -= fabs(dist);
+    minlight = cl_dlights[lnum].minlight;
+    if (rad < minlight)
+      continue;
+    minlight = rad - minlight;
+
+    for (i=0 ; i<3 ; i++)
+    {
+      impact[i] = cl_dlights[lnum].origin[i] -
+          surf->plane->normal[i]*dist;
+    }
+
+    local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
+    local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
+
+    local[0] -= surf->texturemins[0];
+    local[1] -= surf->texturemins[1];
+
+    for (t = 0 ; t<tmax ; t++)
+    {
+      td = (int)(local[1] - t*16);
+      if (td < 0)
+        td = -td;
+      for (s=0 ; s<smax ; s++)
+      {
+        sd = (int)(local[0] - s*16);
+        if (sd < 0)
+          sd = -sd;
+        if (sd > td)
+          dist = sd + (td>>1);
+        else
+          dist = td + (sd>>1);
+        if (dist < minlight)
+          blocklights[t*smax + s] += (int)((rad - dist)*256);
+      }
+    }
+  }
+}
+
+
+/*
+===============
+R_BuildLightMap
+
+Combine and scale multiple lightmaps into the 8.8 format in blocklights
+===============
+*/
+void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
+{
+  int			smax, tmax;
+  int			t;
+  int			i, j, size;
+  byte		*lightmap;
+  unsigned	scale;
+  int			maps;
+  int			lightadj[4];
+  unsigned	*bl;
+
+  surf->cached_dlight = (surf->dlightframe == r_framecount);
+
+  smax = (surf->extents[0]>>4)+1;
+  tmax = (surf->extents[1]>>4)+1;
+  size = smax*tmax;
+  lightmap = surf->samples;
+
+// set to full bright if no light data
+  if (r_fullbright.value || !cl.worldmodel->lightdata)
+  {
+    for (i=0 ; i<size ; i++)
+      blocklights[i] = 255*256;
+    goto store;
+  }
+
+// clear to no light
+  for (i=0 ; i<size ; i++)
+    blocklights[i] = 0;
+
+// add all the lightmaps
+  if (lightmap)
+    for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+       maps++)
+    {
+      scale = d_lightstylevalue[surf->styles[maps]];
+      surf->cached_light[maps] = scale;	// 8.8 fraction
+      for (i=0 ; i<size ; i++)
+        blocklights[i] += lightmap[i] * scale;
+      lightmap += size;	// skip to next lightmap
+    }
+
+// add all the dynamic lights
+  if (surf->dlightframe == r_framecount)
+    R_AddDynamicLights (surf);
+
+// bound, invert, and shift
+store:
+  switch (gl_lightmap_format)
+  {
+  case GL_RGBA:
+    stride -= (smax<<2);
+    bl = blocklights;
+    for (i=0 ; i<tmax ; i++, dest += stride)
+    {
+      for (j=0 ; j<smax ; j++)
+      {
+        t = *bl++;
+        t >>= 7;
+        if (t > 255)
+          t = 255;
+        dest[3] = 255-t;
+        dest += 4;
+      }
+    }
+    break;
+  case GL_ALPHA:
+  case GL_LUMINANCE:
+  case GL_INTENSITY:
+    bl = blocklights;
+    for (i=0 ; i<tmax ; i++, dest += stride)
+    {
+      for (j=0 ; j<smax ; j++)
+      {
+        t = *bl++;
+        t >>= 7;
+        if (t > 255)
+          t = 255;
+        dest[j] = 255-t;
+      }
+    }
+    break;
+  default:
+    Sys_Error ("Bad lightmap format");
+  }
+}
+
+
+/*
+===============
+R_TextureAnimation
+
+Returns the proper texture for a given time and base texture
+===============
+*/
+texture_t *R_TextureAnimation (texture_t *base)
+{
+  int		reletive;
+  int		count;
+
+  if (currententity->frame)
+  {
+    if (base->alternate_anims)
+      base = base->alternate_anims;
+  }
+
+  if (!base->anim_total)
+    return base;
+
+  reletive = (int)(cl.time*10) % base->anim_total;
+
+  count = 0;
+  while (base->anim_min > reletive || base->anim_max <= reletive)
+  {
+    base = base->anim_next;
+    if (!base)
+      Sys_Error ("R_TextureAnimation: broken cycle");
+    if (++count > 100)
+      Sys_Error ("R_TextureAnimation: infinite cycle");
+  }
+
+  return base;
+}
+
+
+/*
+=============================================================
+
+  BRUSH MODELS
+
+=============================================================
+*/
+
+
+extern	int		solidskytexture;
+extern	int		alphaskytexture;
+extern	float	speedscale;		// for top sky and bottom sky
+
+void DrawGLWaterPoly (glpoly_t *p);
+void DrawGLWaterPolyLightmap (glpoly_t *p);
+
+#ifdef _WIN32
+lpMTexFUNC qglMTexCoord2fSGIS = NULL;
+lpSelTexFUNC qglSelectTextureSGIS = NULL;
+#endif
+
+qboolean mtexenabled = false;
+
+void GL_SelectTexture (GLenum target);
+
+void GL_DisableMultitexture(void)
+{
+  if (mtexenabled) {
+    glDisable(GL_TEXTURE_2D);
+    GL_SelectTexture(TEXTURE0_SGIS);
+    mtexenabled = false;
+  }
+}
+
+void GL_EnableMultitexture(void)
+{
+  if (gl_mtexable) {
+    GL_SelectTexture(TEXTURE1_SGIS);
+    glEnable(GL_TEXTURE_2D);
+    mtexenabled = true;
+  }
+}
+
+#if 0
+/*
+================
+R_DrawSequentialPoly
+
+Systems that have fast state and texture changes can
+just do everything as it passes with no need to sort
+================
+*/
+void R_DrawSequentialPoly (msurface_t *s)
+{
+  glpoly_t	*p;
+  float		*v;
+  int			i;
+  texture_t	*t;
+
+  //
+  // normal lightmaped poly
+  //
+  if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
+  {
+    p = s->polys;
+
+    t = R_TextureAnimation (s->texinfo->texture);
+    GL_Bind (t->gl_texturenum);
+    glBegin (GL_POLYGON);
+    v = p->verts[0];
+    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+    {
+      glTexCoord2f (v[3], v[4]);
+      glVertex3fv (v);
+    }
+    glEnd ();
+
+    GL_Bind (lightmap_textures + s->lightmaptexturenum);
+    glEnable (GL_BLEND);
+    glBegin (GL_POLYGON);
+    v = p->verts[0];
+    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+    {
+      glTexCoord2f (v[5], v[6]);
+      glVertex3fv (v);
+    }
+    glEnd ();
+
+    glDisable (GL_BLEND);
+
+    return;
+  }
+
+  //
+  // subdivided water surface warp
+  //
+  if (s->flags & SURF_DRAWTURB)
+  {
+    GL_Bind (s->texinfo->texture->gl_texturenum);
+    EmitWaterPolys (s);
+    return;
+  }
+
+  //
+  // subdivided sky warp
+  //
+  if (s->flags & SURF_DRAWSKY)
+  {
+    GL_Bind (solidskytexture);
+    speedscale = realtime*8;
+    speedscale -= (int)speedscale;
+
+    EmitSkyPolys (s);
+
+    glEnable (GL_BLEND);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    GL_Bind (alphaskytexture);
+    speedscale = realtime*16;
+    speedscale -= (int)speedscale;
+    EmitSkyPolys (s);
+    if (gl_lightmap_format == GL_LUMINANCE)
+      glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+
+    glDisable (GL_BLEND);
+  }
+
+  //
+  // underwater warped with lightmap
+  //
+  p = s->polys;
+
+  t = R_TextureAnimation (s->texinfo->texture);
+  GL_Bind (t->gl_texturenum);
+  DrawGLWaterPoly (p);
+
+  GL_Bind (lightmap_textures + s->lightmaptexturenum);
+  glEnable (GL_BLEND);
+  DrawGLWaterPolyLightmap (p);
+  glDisable (GL_BLEND);
+}
+#else
+/*
+================
+R_DrawSequentialPoly
+
+Systems that have fast state and texture changes can
+just do everything as it passes with no need to sort
+================
+*/
+void R_DrawSequentialPoly (msurface_t *s)
+{
+  glpoly_t	*p;
+  float		*v;
+  int			i;
+  texture_t	*t;
+  vec3_t		nv, dir;
+  float		ss, ss2, length;
+  float		s1, t1;
+  glRect_t	*theRect;
+
+  //
+  // normal lightmaped poly
+  //
+
+  if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
+  {
+    R_RenderDynamicLightmaps (s);
+    if (gl_mtexable) {
+      p = s->polys;
+
+      t = R_TextureAnimation (s->texinfo->texture);
+      // Binds world to texture env 0
+      GL_SelectTexture(TEXTURE0_SGIS);
+      GL_Bind (t->gl_texturenum);
+      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+      // Binds lightmap to texenv 1
+      GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
+      GL_Bind (lightmap_textures + s->lightmaptexturenum);
+      i = s->lightmaptexturenum;
+      if (lightmap_modified[i])
+      {
+        lightmap_modified[i] = false;
+        theRect = &lightmap_rectchange[i];
+        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
+          BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
+          lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
+        theRect->l = BLOCK_WIDTH;
+        theRect->t = BLOCK_HEIGHT;
+        theRect->h = 0;
+        theRect->w = 0;
+      }
+      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
+
+#ifdef USE_OPENGLES
+
+      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
+            glClientActiveTexture(GL_TEXTURE1);
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
+      glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
+            glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+            glClientActiveTexture(GL_TEXTURE0);
+
+#else
+      glBegin(GL_POLYGON);
+      v = p->verts[0];
+      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+      {
+        qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
+        qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
+        glVertex3fv (v);
+      }
+      glEnd ();
+#endif
+      return;
+    } else {
+      p = s->polys;
+
+      t = R_TextureAnimation (s->texinfo->texture);
+      GL_Bind (t->gl_texturenum);
+#ifdef USE_OPENGLES
+      glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
+      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
+      glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+#else
+      glBegin (GL_POLYGON);
+      v = p->verts[0];
+      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+      {
+        glTexCoord2f (v[3], v[4]);
+        glVertex3fv (v);
+      }
+      glEnd ();
+#endif
+
+      GL_Bind (lightmap_textures + s->lightmaptexturenum);
+      glEnable (GL_BLEND);
+#ifdef USE_OPENGLES
+      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
+      glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+#else
+      glBegin (GL_POLYGON);
+      v = p->verts[0];
+      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+      {
+        glTexCoord2f (v[5], v[6]);
+        glVertex3fv (v);
+      }
+      glEnd ();
+#endif
+
+      glDisable (GL_BLEND);
+    }
+
+    return;
+  }
+
+  //
+  // subdivided water surface warp
+  //
+
+  if (s->flags & SURF_DRAWTURB)
+  {
+    GL_DisableMultitexture();
+    GL_Bind (s->texinfo->texture->gl_texturenum);
+    EmitWaterPolys (s);
+    return;
+  }
+
+  //
+  // subdivided sky warp
+  //
+  if (s->flags & SURF_DRAWSKY)
+  {
+    GL_DisableMultitexture();
+    GL_Bind (solidskytexture);
+    speedscale = realtime*8;
+    speedscale -= (int)speedscale & ~127;
+
+    EmitSkyPolys (s);
+
+    glEnable (GL_BLEND);
+    GL_Bind (alphaskytexture);
+    speedscale = realtime*16;
+    speedscale -= (int)speedscale & ~127;
+    EmitSkyPolys (s);
+
+    glDisable (GL_BLEND);
+    return;
+  }
+
+  //
+  // underwater warped with lightmap
+  //
+  R_RenderDynamicLightmaps (s);
+  if (gl_mtexable) {
+    p = s->polys;
+
+    t = R_TextureAnimation (s->texinfo->texture);
+    GL_SelectTexture(TEXTURE0_SGIS);
+    GL_Bind (t->gl_texturenum);
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    GL_EnableMultitexture();
+    GL_Bind (lightmap_textures + s->lightmaptexturenum);
+    i = s->lightmaptexturenum;
+    if (lightmap_modified[i])
+    {
+      lightmap_modified[i] = false;
+      theRect = &lightmap_rectchange[i];
+      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
+        BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
+        lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
+      theRect->l = BLOCK_WIDTH;
+      theRect->t = BLOCK_HEIGHT;
+      theRect->h = 0;
+      theRect->w = 0;
+    }
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
+#ifdef USE_OPENGLES
+    {
+      float* pPos = gVertexBuffer;
+      v = p->verts[0];
+      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+      {
+        *pPos++ = v[0] + 8*sinf(v[1]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
+        *pPos++ = v[1] + 8*sinf(v[0]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
+        *pPos++ = v[2];
+      }
+    }
+        glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
+        glClientActiveTexture(GL_TEXTURE1);
+        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
+        glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        glClientActiveTexture(GL_TEXTURE0);
+#else
+    glBegin (GL_TRIANGLE_FAN);
+    v = p->verts[0];
+    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+    {
+      qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
+      qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
+
+      nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
+      nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
+      nv[2] = v[2];
+
+      glVertex3fv (nv);
+    }
+    glEnd ();
+#endif
+
+  } else {
+    p = s->polys;
+
+    t = R_TextureAnimation (s->texinfo->texture);
+    GL_Bind (t->gl_texturenum);
+    DrawGLWaterPoly (p);
+
+    GL_Bind (lightmap_textures + s->lightmaptexturenum);
+    glEnable (GL_BLEND);
+    DrawGLWaterPolyLightmap (p);
+    glDisable (GL_BLEND);
+  }
+}
+#endif
+
+
+/*
+================
+DrawGLWaterPoly
+
+Warp the vertex coordinates
+================
+*/
+void DrawGLWaterPoly (glpoly_t *p)
+{
+  int		i;
+  float	*v;
+  float	s, t, os, ot;
+  vec3_t	nv;
+
+  GL_DisableMultitexture();
+
+#ifdef USE_OPENGLES
+  glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
+  glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
+
+  v = p->verts[0];
+  {
+    float* pnv = gVertexBuffer;
+    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+    {
+      pnv[0] = v[0] + 8*sinf(v[1]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
+      pnv[1] = v[1] + 8*sinf(v[0]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
+      pnv[2] = v[2];
+
+      pnv += 3;
+    }
+  }
+  glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+#else
+  glBegin (GL_TRIANGLE_FAN);
+  v = p->verts[0];
+  for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+  {
+    glTexCoord2f (v[3], v[4]);
+
+    nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
+    nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
+    nv[2] = v[2];
+
+    glVertex3fv (nv);
+  }
+  glEnd ();
+#endif
+}
+
+void DrawGLWaterPolyLightmap (glpoly_t *p)
+{
+  int		i;
+  float	*v;
+  float	s, t, os, ot;
+  vec3_t	nv;
+
+  GL_DisableMultitexture();
+
+#ifdef USE_OPENGLES
+  glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
+  glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
+
+  v = p->verts[0];
+  {
+    float* pnv = gVertexBuffer;
+    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+    {
+      pnv[0] = v[0] + 8*sinf(v[1]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
+      pnv[1] = v[1] + 8*sinf(v[0]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
+      pnv[2] = v[2];
+
+      pnv += 3;
+    }
+  }
+  glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+
+#else
+  glBegin (GL_TRIANGLE_FAN);
+  v = p->verts[0];
+  for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+  {
+    glTexCoord2f (v[5], v[6]);
+
+    nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
+    nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
+    nv[2] = v[2];
+
+    glVertex3fv (nv);
+  }
+  glEnd ();
+#endif
+}
+
+/*
+================
+DrawGLPoly
+================
+*/
+void DrawGLPoly (glpoly_t *p)
+{
+  int		i;
+  float	*v;
+
+#ifdef USE_OPENGLES
+  glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
+  glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
+  glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+#else
+  glBegin (GL_POLYGON);
+  v = p->verts[0];
+  for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
+  {
+    glTexCoord2f (v[3], v[4]);
+    glVertex3fv (v);
+  }
+  glEnd ();
+#endif
+}
+
+
+/*
+================
+R_BlendLightmaps
+================
+*/
+void R_BlendLightmaps (void)
+{
+  int			i, j;
+  glpoly_t	*p;
+  float		*v;
+  glRect_t	*theRect;
+
+  if (r_fullbright.value)
+    return;
+  if (!gl_texsort.value)
+    return;
+
+  glDepthMask (0);		// don't bother writing Z
+
+  if (gl_lightmap_format == GL_LUMINANCE)
+    glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+  else if (gl_lightmap_format == GL_INTENSITY)
+  {
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    glColor4f (0,0,0,1);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  }
+
+  if (!r_lightmap.value)
+  {
+    glEnable (GL_BLEND);
+  }
+
+  for (i=0 ; i<MAX_LIGHTMAPS ; i++)
+  {
+    p = lightmap_polys[i];
+    if (!p)
+      continue;
+    GL_Bind(lightmap_textures+i);
+    if (lightmap_modified[i])
+    {
+      lightmap_modified[i] = false;
+      theRect = &lightmap_rectchange[i];
+//			glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
+//			, BLOCK_WIDTH, BLOCK_HEIGHT, 0,
+//			gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
+//			glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
+//				, BLOCK_WIDTH, theRect->h, 0,
+//				gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+(i*BLOCK_HEIGHT+theRect->t)*BLOCK_WIDTH*lightmap_bytes);
+      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
+        BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
+        lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
+      theRect->l = BLOCK_WIDTH;
+      theRect->t = BLOCK_HEIGHT;
+      theRect->h = 0;
+      theRect->w = 0;
+    }
+    for ( ; p ; p=p->chain)
+    {
+      if (p->flags & SURF_UNDERWATER)
+        DrawGLWaterPolyLightmap (p);
+      else
+      {
+#ifdef USE_OPENGLES
+        glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
+        glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+#else
+        glBegin (GL_POLYGON);
+        v = p->verts[0];
+        for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
+        {
+          glTexCoord2f (v[5], v[6]);
+          glVertex3fv (v);
+        }
+        glEnd ();
+#endif
+      }
+    }
+  }
+
+  glDisable (GL_BLEND);
+  if (gl_lightmap_format == GL_LUMINANCE)
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  else if (gl_lightmap_format == GL_INTENSITY)
+  {
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glColor4f (1,1,1,1);
+  }
+
+  glDepthMask (1);		// back to normal Z buffering
+}
+
+/*
+================
+R_RenderBrushPoly
+================
+*/
+void R_RenderBrushPoly (msurface_t *fa)
+{
+  texture_t	*t;
+  byte		*base;
+  int			maps;
+  glRect_t    *theRect;
+  int smax, tmax;
+
+  c_brush_polys++;
+
+  if (fa->flags & SURF_DRAWSKY)
+  {	// warp texture, no lightmaps
+    EmitBothSkyLayers (fa);
+    return;
+  }
+
+  t = R_TextureAnimation (fa->texinfo->texture);
+  GL_Bind (t->gl_texturenum);
+
+  if (fa->flags & SURF_DRAWTURB)
+  {	// warp texture, no lightmaps
+    EmitWaterPolys (fa);
+    return;
+  }
+
+  if (fa->flags & SURF_UNDERWATER)
+    DrawGLWaterPoly (fa->polys);
+  else
+    DrawGLPoly (fa->polys);
+
+  // add the poly to the proper lightmap chain
+
+  fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
+  lightmap_polys[fa->lightmaptexturenum] = fa->polys;
+
+  // check for lightmap modification
+  for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
+     maps++)
+    if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
+      goto dynamic;
+
+  if (fa->dlightframe == r_framecount	// dynamic this frame
+    || fa->cached_dlight)			// dynamic previously
+  {
+dynamic:
+    if (r_dynamic.value)
+    {
+      lightmap_modified[fa->lightmaptexturenum] = true;
+      theRect = &lightmap_rectchange[fa->lightmaptexturenum];
+      if (fa->light_t < theRect->t) {
+        if (theRect->h)
+          theRect->h += theRect->t - fa->light_t;
+        theRect->t = fa->light_t;
+      }
+      if (fa->light_s < theRect->l) {
+        if (theRect->w)
+          theRect->w += theRect->l - fa->light_s;
+        theRect->l = fa->light_s;
+      }
+      smax = (fa->extents[0]>>4)+1;
+      tmax = (fa->extents[1]>>4)+1;
+      if ((theRect->w + theRect->l) < (fa->light_s + smax))
+        theRect->w = (fa->light_s-theRect->l)+smax;
+      if ((theRect->h + theRect->t) < (fa->light_t + tmax))
+        theRect->h = (fa->light_t-theRect->t)+tmax;
+      base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
+      base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
+      R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
+    }
+  }
+}
+
+/*
+================
+R_RenderDynamicLightmaps
+Multitexture
+================
+*/
+void R_RenderDynamicLightmaps (msurface_t *fa)
+{
+  texture_t	*t;
+  byte		*base;
+  int			maps;
+  glRect_t    *theRect;
+  int smax, tmax;
+
+  c_brush_polys++;
+
+  if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) )
+    return;
+
+  fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
+  lightmap_polys[fa->lightmaptexturenum] = fa->polys;
+
+  // check for lightmap modification
+  for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
+     maps++)
+    if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
+      goto dynamic;
+
+  if (fa->dlightframe == r_framecount	// dynamic this frame
+    || fa->cached_dlight)			// dynamic previously
+  {
+dynamic:
+    if (r_dynamic.value)
+    {
+      lightmap_modified[fa->lightmaptexturenum] = true;
+      theRect = &lightmap_rectchange[fa->lightmaptexturenum];
+      if (fa->light_t < theRect->t) {
+        if (theRect->h)
+          theRect->h += theRect->t - fa->light_t;
+        theRect->t = fa->light_t;
+      }
+      if (fa->light_s < theRect->l) {
+        if (theRect->w)
+          theRect->w += theRect->l - fa->light_s;
+        theRect->l = fa->light_s;
+      }
+      smax = (fa->extents[0]>>4)+1;
+      tmax = (fa->extents[1]>>4)+1;
+      if ((theRect->w + theRect->l) < (fa->light_s + smax))
+        theRect->w = (fa->light_s-theRect->l)+smax;
+      if ((theRect->h + theRect->t) < (fa->light_t + tmax))
+        theRect->h = (fa->light_t-theRect->t)+tmax;
+      base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
+      base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
+      R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
+    }
+  }
+}
+
+/*
+================
+R_MirrorChain
+================
+*/
+void R_MirrorChain (msurface_t *s)
+{
+  if (mirror)
+    return;
+  mirror = true;
+  mirror_plane = s->plane;
+}
+
+
+#if 0
+/*
+================
+R_DrawWaterSurfaces
+================
+*/
+void R_DrawWaterSurfaces (void)
+{
+  int			i;
+  msurface_t	*s;
+  texture_t	*t;
+
+  if (r_wateralpha.value == 1.0)
+    return;
+
+  //
+  // go back to the world matrix
+  //
+    glLoadMatrixf (r_world_matrix);
+
+  glEnable (GL_BLEND);
+  glColor4f (1,1,1,r_wateralpha.value);
+  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+  for (i=0 ; i<cl.worldmodel->numtextures ; i++)
+  {
+    t = cl.worldmodel->textures[i];
+    if (!t)
+      continue;
+    s = t->texturechain;
+    if (!s)
+      continue;
+    if ( !(s->flags & SURF_DRAWTURB) )
+      continue;
+
+    // set modulate mode explicitly
+    GL_Bind (t->gl_texturenum);
+
+    for ( ; s ; s=s->texturechain)
+      R_RenderBrushPoly (s);
+
+    t->texturechain = NULL;
+  }
+
+  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+  glColor4f (1,1,1,1);
+  glDisable (GL_BLEND);
+}
+#else
+/*
+================
+R_DrawWaterSurfaces
+================
+*/
+void R_DrawWaterSurfaces (void)
+{
+  int			i;
+  msurface_t	*s;
+  texture_t	*t;
+
+  if (r_wateralpha.value == 1.0 && gl_texsort.value)
+    return;
+
+  //
+  // go back to the world matrix
+  //
+
+    glLoadMatrixf (r_world_matrix);
+
+  if (r_wateralpha.value < 1.0) {
+    glEnable (GL_BLEND);
+    glColor4f (1,1,1,r_wateralpha.value);
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+  }
+
+  if (!gl_texsort.value) {
+    if (!waterchain)
+      return;
+
+    for ( s = waterchain ; s ; s=s->texturechain) {
+      GL_Bind (s->texinfo->texture->gl_texturenum);
+      EmitWaterPolys (s);
+    }
+
+    waterchain = NULL;
+  } else {
+
+    for (i=0 ; i<cl.worldmodel->numtextures ; i++)
+    {
+      t = cl.worldmodel->textures[i];
+      if (!t)
+        continue;
+      s = t->texturechain;
+      if (!s)
+        continue;
+      if ( !(s->flags & SURF_DRAWTURB ) )
+        continue;
+
+      // set modulate mode explicitly
+
+      GL_Bind (t->gl_texturenum);
+
+      for ( ; s ; s=s->texturechain)
+        EmitWaterPolys (s);
+
+      t->texturechain = NULL;
+    }
+
+  }
+
+  if (r_wateralpha.value < 1.0) {
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+    glColor4f (1,1,1,1);
+    glDisable (GL_BLEND);
+  }
+
+}
+
+#endif
+
+/*
+================
+DrawTextureChains
+================
+*/
+void DrawTextureChains (void)
+{
+  int		i;
+  msurface_t	*s;
+  texture_t	*t;
+
+  if (!gl_texsort.value) {
+    GL_DisableMultitexture();
+
+    if (skychain) {
+      R_DrawSkyChain(skychain);
+      skychain = NULL;
+    }
+
+    return;
+  }
+
+  for (i=0 ; i<cl.worldmodel->numtextures ; i++)
+  {
+    t = cl.worldmodel->textures[i];
+    if (!t)
+      continue;
+    s = t->texturechain;
+    if (!s)
+      continue;
+    if (i == skytexturenum)
+      R_DrawSkyChain (s);
+    else if (i == mirrortexturenum && r_mirroralpha.value != 1.0)
+    {
+      R_MirrorChain (s);
+      continue;
+    }
+    else
+    {
+      if ((s->flags & SURF_DRAWTURB) && r_wateralpha.value != 1.0)
+        continue;	// draw translucent water later
+      for ( ; s ; s=s->texturechain)
+        R_RenderBrushPoly (s);
+    }
+
+    t->texturechain = NULL;
+  }
+}
+
+/*
+=================
+R_DrawBrushModel
+=================
+*/
+void R_DrawBrushModel (entity_t *e)
+{
+  int			j, k;
+  vec3_t		mins, maxs;
+  int			i, numsurfaces;
+  msurface_t	*psurf;
+  float		dot;
+  mplane_t	*pplane;
+  model_t		*clmodel;
+  qboolean	rotated;
+
+  currententity = e;
+  currenttexture = -1;
+
+  clmodel = e->model;
+
+  if (e->angles[0] || e->angles[1] || e->angles[2])
+  {
+    rotated = true;
+    for (i=0 ; i<3 ; i++)
+    {
+      mins[i] = e->origin[i] - clmodel->radius;
+      maxs[i] = e->origin[i] + clmodel->radius;
+    }
+  }
+  else
+  {
+    rotated = false;
+    VectorAdd (e->origin, clmodel->mins, mins);
+    VectorAdd (e->origin, clmodel->maxs, maxs);
+  }
+
+  if (R_CullBox (mins, maxs))
+    return;
+
+  glColor3f (1,1,1);
+  memset (lightmap_polys, 0, sizeof(lightmap_polys));
+
+  VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
+  if (rotated)
+  {
+    vec3_t	temp;
+    vec3_t	forward, right, up;
+
+    VectorCopy (modelorg, temp);
+    AngleVectors (e->angles, forward, right, up);
+    modelorg[0] = DotProduct (temp, forward);
+    modelorg[1] = -DotProduct (temp, right);
+    modelorg[2] = DotProduct (temp, up);
+  }
+
+  psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
+
+// calculate dynamic lighting for bmodel if it's not an
+// instanced model
+  if (clmodel->firstmodelsurface != 0 && !gl_flashblend.value)
+  {
+    for (k=0 ; k<MAX_DLIGHTS ; k++)
+    {
+      if ((cl_dlights[k].die < cl.time) ||
+        (!cl_dlights[k].radius))
+        continue;
+
+      R_MarkLights (&cl_dlights[k], 1<<k,
+        clmodel->nodes + clmodel->hulls[0].firstclipnode);
+    }
+  }
+
+    glPushMatrix ();
+e->angles[0] = -e->angles[0];	// stupid quake bug
+  R_RotateForEntity (e);
+e->angles[0] = -e->angles[0];	// stupid quake bug
+
+  //
+  // draw texture
+  //
+  for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
+  {
+  // find which side of the node we are on
+    pplane = psurf->plane;
+
+    dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
+
+  // draw the polygon
+    if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
+      (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
+    {
+      if (gl_texsort.value)
+        R_RenderBrushPoly (psurf);
+      else
+        R_DrawSequentialPoly (psurf);
+    }
+  }
+
+  R_BlendLightmaps ();
+
+  glPopMatrix ();
+}
+
+/*
+=============================================================
+
+  WORLD MODEL
+
+=============================================================
+*/
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+void R_RecursiveWorldNode (mnode_t *node)
+{
+  int			i, c, side, *pindex;
+  vec3_t		acceptpt, rejectpt;
+  mplane_t	*plane;
+  msurface_t	*surf, **mark;
+  mleaf_t		*pleaf;
+  double		d, dot;
+  vec3_t		mins, maxs;
+
+  if (node->contents == CONTENTS_SOLID)
+    return;		// solid
+
+  if (node->visframe != r_visframecount)
+    return;
+  if (R_CullBox (node->minmaxs, node->minmaxs+3))
+    return;
+
+// if a leaf node, draw stuff
+  if (node->contents < 0)
+  {
+    pleaf = (mleaf_t *)node;
+
+    mark = pleaf->firstmarksurface;
+    c = pleaf->nummarksurfaces;
+
+    if (c)
+    {
+      do
+      {
+        (*mark)->visframe = r_framecount;
+        mark++;
+      } while (--c);
+    }
+
+  // deal with model fragments in this leaf
+    if (pleaf->efrags)
+      R_StoreEfrags (&pleaf->efrags);
+
+    return;
+  }
+
+// node is just a decision point, so go down the apropriate sides
+
+// find which side of the node we are on
+  plane = node->plane;
+
+  switch (plane->type)
+  {
+  case PLANE_X:
+    dot = modelorg[0] - plane->dist;
+    break;
+  case PLANE_Y:
+    dot = modelorg[1] - plane->dist;
+    break;
+  case PLANE_Z:
+    dot = modelorg[2] - plane->dist;
+    break;
+  default:
+    dot = DotProduct (modelorg, plane->normal) - plane->dist;
+    break;
+  }
+
+  if (dot >= 0)
+    side = 0;
+  else
+    side = 1;
+
+// recurse down the children, front side first
+  R_RecursiveWorldNode (node->children[side]);
+
+// draw stuff
+  c = node->numsurfaces;
+
+  if (c)
+  {
+    surf = cl.worldmodel->surfaces + node->firstsurface;
+
+    if (dot < 0 -BACKFACE_EPSILON)
+      side = SURF_PLANEBACK;
+    else if (dot > BACKFACE_EPSILON)
+      side = 0;
+    {
+      for ( ; c ; c--, surf++)
+      {
+        if (surf->visframe != r_framecount)
+          continue;
+
+        // don't backface underwater surfaces, because they warp
+        if ( !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
+          continue;		// wrong side
+
+        // if sorting by texture, just store it out
+        if (gl_texsort.value)
+        {
+          if (!mirror
+          || surf->texinfo->texture != cl.worldmodel->textures[mirrortexturenum])
+          {
+            surf->texturechain = surf->texinfo->texture->texturechain;
+            surf->texinfo->texture->texturechain = surf;
+          }
+        } else if (surf->flags & SURF_DRAWSKY) {
+          surf->texturechain = skychain;
+          skychain = surf;
+        } else if (surf->flags & SURF_DRAWTURB) {
+          surf->texturechain = waterchain;
+          waterchain = surf;
+        } else
+          R_DrawSequentialPoly (surf);
+
+      }
+    }
+
+  }
+
+// recurse down the back side
+  R_RecursiveWorldNode (node->children[!side]);
+}
+
+
+
+/*
+=============
+R_DrawWorld
+=============
+*/
+void R_DrawWorld (void)
+{
+  entity_t	ent;
+  int			i;
+
+  memset (&ent, 0, sizeof(ent));
+  ent.model = cl.worldmodel;
+
+  VectorCopy (r_refdef.vieworg, modelorg);
+
+  currententity = &ent;
+  currenttexture = -1;
+
+  glColor3f (1,1,1);
+  memset (lightmap_polys, 0, sizeof(lightmap_polys));
+#ifdef QUAKE2
+  R_ClearSkyBox ();
+#endif
+
+  R_RecursiveWorldNode (cl.worldmodel->nodes);
+
+  DrawTextureChains ();
+
+  R_BlendLightmaps ();
+
+#ifdef QUAKE2
+  R_DrawSkyBox ();
+#endif
+}
+
+
+/*
+===============
+R_MarkLeaves
+===============
+*/
+void R_MarkLeaves (void)
+{
+  byte	*vis;
+  mnode_t	*node;
+  int		i;
+  byte	solid[4096];
+
+  if (r_oldviewleaf == r_viewleaf && !r_novis.value)
+    return;
+
+  if (mirror)
+    return;
+
+  r_visframecount++;
+  r_oldviewleaf = r_viewleaf;
+
+  if (r_novis.value)
+  {
+    vis = solid;
+    memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);
+  }
+  else
+    vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
+
+  for (i=0 ; i<cl.worldmodel->numleafs ; i++)
+  {
+    if (vis[i>>3] & (1<<(i&7)))
+    {
+      node = (mnode_t *)&cl.worldmodel->leafs[i+1];
+      do
+      {
+        if (node->visframe == r_visframecount)
+          break;
+        node->visframe = r_visframecount;
+        node = node->parent;
+      } while (node);
+    }
+  }
+}
+
+
+
+/*
+=============================================================================
+
+  LIGHTMAP ALLOCATION
+
+=============================================================================
+*/
+
+// returns a texture number and the position inside it
+int AllocBlock (int w, int h, int *x, int *y)
+{
+  int		i, j;
+  int		best, best2;
+  int		bestx;
+  int		texnum;
+
+  for (texnum=0 ; texnum<MAX_LIGHTMAPS ; texnum++)
+  {
+    best = BLOCK_HEIGHT;
+
+    for (i=0 ; i<BLOCK_WIDTH-w ; i++)
+    {
+      best2 = 0;
+
+      for (j=0 ; j<w ; j++)
+      {
+        if (allocated[texnum][i+j] >= best)
+          break;
+        if (allocated[texnum][i+j] > best2)
+          best2 = allocated[texnum][i+j];
+      }
+      if (j == w)
+      {	// this is a valid spot
+        *x = i;
+        *y = best = best2;
+      }
+    }
+
+    if (best + h > BLOCK_HEIGHT)
+      continue;
+
+    for (i=0 ; i<w ; i++)
+      allocated[texnum][*x + i] = best + h;
+
+    return texnum;
+  }
+
+  Sys_Error ("AllocBlock: full");
+  return 0;
+}
+
+
+mvertex_t	*r_pcurrentvertbase;
+model_t		*currentmodel;
+
+int	nColinElim;
+
+/*
+================
+BuildSurfaceDisplayList
+================
+*/
+void BuildSurfaceDisplayList (msurface_t *fa)
+{
+  int			i, lindex, lnumverts, s_axis, t_axis;
+  float		dist, lastdist, lzi, scale, u, v, frac;
+  unsigned	mask;
+  vec3_t		local, transformed;
+  medge_t		*pedges, *r_pedge;
+  mplane_t	*pplane;
+  int			vertpage, newverts, newpage, lastvert;
+  qboolean	visible;
+  float		*vec;
+  float		s, t;
+  glpoly_t	*poly;
+
+// reconstruct the polygon
+  pedges = currentmodel->edges;
+  lnumverts = fa->numedges;
+  vertpage = 0;
+
+  //
+  // draw texture
+  //
+  poly = (glpoly_t*) Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));
+  poly->next = fa->polys;
+  poly->flags = fa->flags;
+  fa->polys = poly;
+  poly->numverts = lnumverts;
+
+  for (i=0 ; i<lnumverts ; i++)
+  {
+    lindex = currentmodel->surfedges[fa->firstedge + i];
+
+    if (lindex > 0)
+    {
+      r_pedge = &pedges[lindex];
+      vec = r_pcurrentvertbase[r_pedge->v[0]].position;
+    }
+    else
+    {
+      r_pedge = &pedges[-lindex];
+      vec = r_pcurrentvertbase[r_pedge->v[1]].position;
+    }
+    s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
+    s /= fa->texinfo->texture->width;
+
+    t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
+    t /= fa->texinfo->texture->height;
+
+    VectorCopy (vec, poly->verts[i]);
+    poly->verts[i][3] = s;
+    poly->verts[i][4] = t;
+
+    //
+    // lightmap texture coordinates
+    //
+    s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
+    s -= fa->texturemins[0];
+    s += fa->light_s*16;
+    s += 8;
+    s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
+
+    t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
+    t -= fa->texturemins[1];
+    t += fa->light_t*16;
+    t += 8;
+    t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
+
+    poly->verts[i][5] = s;
+    poly->verts[i][6] = t;
+  }
+
+  //
+  // remove co-linear points - Ed
+  //
+  if (!gl_keeptjunctions.value && !(fa->flags & SURF_UNDERWATER) )
+  {
+    for (i = 0 ; i < lnumverts ; ++i)
+    {
+      vec3_t v1, v2;
+      float *prev, *thiz, *next;
+      float f;
+
+      prev = poly->verts[(i + lnumverts - 1) % lnumverts];
+      thiz = poly->verts[i];
+      next = poly->verts[(i + 1) % lnumverts];
+
+      VectorSubtract( thiz, prev, v1 );
+      VectorNormalize( v1 );
+      VectorSubtract( next, prev, v2 );
+      VectorNormalize( v2 );
+
+      // skip co-linear points
+      #define COLINEAR_EPSILON 0.001
+      if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
+        (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) &&
+        (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
+      {
+        int j;
+        for (j = i + 1; j < lnumverts; ++j)
+        {
+          int k;
+          for (k = 0; k < VERTEXSIZE; ++k)
+            poly->verts[j - 1][k] = poly->verts[j][k];
+        }
+        --lnumverts;
+        ++nColinElim;
+        // retry next vertex next time, which is now current vertex
+        --i;
+      }
+    }
+  }
+  poly->numverts = lnumverts;
+
+}
+
+/*
+========================
+GL_CreateSurfaceLightmap
+========================
+*/
+void GL_CreateSurfaceLightmap (msurface_t *surf)
+{
+  int		smax, tmax, s, t, l, i;
+  byte	*base;
+
+  if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
+    return;
+
+  smax = (surf->extents[0]>>4)+1;
+  tmax = (surf->extents[1]>>4)+1;
+
+  surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
+  base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
+  base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
+  R_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes);
+}
+
+
+
+void GL_UploadLightmaps()
+{
+   if (!gl_texsort.value)
+     GL_SelectTexture(TEXTURE1_SGIS);
+
+  //
+  // upload all lightmaps that were filled
+  //
+  for (int i=0 ; i<MAX_LIGHTMAPS ; i++)
+  {
+    if (!allocated[i][0])
+      break;		// no more used
+    lightmap_modified[i] = false;
+    lightmap_rectchange[i].l = BLOCK_WIDTH;
+    lightmap_rectchange[i].t = BLOCK_HEIGHT;
+    lightmap_rectchange[i].w = 0;
+    lightmap_rectchange[i].h = 0;
+    GL_Bind(lightmap_textures + i);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
+    , BLOCK_WIDTH, BLOCK_HEIGHT, 0,
+    gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
+  }
+
+   if (!gl_texsort.value)
+     GL_SelectTexture(TEXTURE0_SGIS);
+
+}
+
+/*
+==================
+GL_BuildLightmaps
+
+Builds the lightmap texture
+with all the surfaces from all brush models
+==================
+*/
+void GL_BuildLightmaps (void)
+{
+  int		i, j;
+  model_t	*m;
+  extern qboolean isPermedia;
+
+  memset (allocated, 0, sizeof(allocated));
+
+  r_framecount = 1;		// no dlightcache
+
+  if (!lightmap_textures)
+  {
+    lightmap_textures = texture_extension_number;
+    texture_extension_number += MAX_LIGHTMAPS;
+  }
+
+  gl_lightmap_format = GL_LUMINANCE;
+  // default differently on the Permedia
+  if (isPermedia)
+    gl_lightmap_format = GL_RGBA;
+
+  if (COM_CheckParm ("-lm_1"))
+    gl_lightmap_format = GL_LUMINANCE;
+  if (COM_CheckParm ("-lm_a"))
+    gl_lightmap_format = GL_ALPHA;
+  if (COM_CheckParm ("-lm_i"))
+    gl_lightmap_format = GL_INTENSITY;
+  if (COM_CheckParm ("-lm_2"))
+    gl_lightmap_format = GL_RGBA4;
+  if (COM_CheckParm ("-lm_4"))
+    gl_lightmap_format = GL_RGBA;
+
+  switch (gl_lightmap_format)
+  {
+  case GL_RGBA:
+    lightmap_bytes = 4;
+    break;
+  case GL_RGBA4:
+    lightmap_bytes = 2;
+    break;
+  case GL_LUMINANCE:
+  case GL_INTENSITY:
+  case GL_ALPHA:
+    lightmap_bytes = 1;
+    break;
+  }
+
+  for (j=1 ; j<MAX_MODELS ; j++)
+  {
+    m = cl.model_precache[j];
+    if (!m)
+      break;
+    if (m->name[0] == '*')
+      continue;
+    r_pcurrentvertbase = m->vertexes;
+    currentmodel = m;
+    for (i=0 ; i<m->numsurfaces ; i++)
+    {
+      GL_CreateSurfaceLightmap (m->surfaces + i);
+      if ( m->surfaces[i].flags & SURF_DRAWTURB )
+        continue;
+#ifndef QUAKE2
+      if ( m->surfaces[i].flags & SURF_DRAWSKY )
+        continue;
+#endif
+      BuildSurfaceDisplayList (m->surfaces + i);
+    }
+  }
+
+  GL_UploadLightmaps();
+}
+
+
diff --git a/quake/src/WinQuake/gl_screen.c b/quake/src/WinQuake/gl_screen.cpp
old mode 100644
new mode 100755
similarity index 87%
rename from quake/src/WinQuake/gl_screen.c
rename to quake/src/WinQuake/gl_screen.cpp
index cd43d17..1748f92
--- a/quake/src/WinQuake/gl_screen.c
+++ b/quake/src/WinQuake/gl_screen.cpp
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 // screen.c -- master for refresh, status bar, console, chat, notify, etc
 
@@ -55,7 +55,7 @@
 Screen_Update ();
 Con_Printf ();
 
-net 
+net
 turn off messages option
 
 the refresh is allways rendered, unless the console is full screen
@@ -65,14 +65,14 @@
 	notify lines
 	half
 	full
-	
+
 
 */
 
 
 int			glx, gly, glwidth, glheight;
 
-// only the refresh window will be updated unless these variables are flagged 
+// only the refresh window will be updated unless these variables are flagged
 int			scr_copytop;
 int			scr_copyeverything;
 
@@ -80,16 +80,16 @@
 float		scr_conlines;		// lines of console to display
 
 float		oldscreensize, oldfov;
-cvar_t		scr_viewsize = {"viewsize","100", true};
-cvar_t		scr_fov = {"fov","90"};	// 10 - 170
-cvar_t		scr_conspeed = {"scr_conspeed","300"};
-cvar_t		scr_centertime = {"scr_centertime","2"};
-cvar_t		scr_showram = {"showram","1"};
-cvar_t		scr_showturtle = {"showturtle","0"};
-cvar_t		scr_showpause = {"showpause","1"};
-cvar_t		scr_printspeed = {"scr_printspeed","8"};
-cvar_t		gl_triplebuffer = {"gl_triplebuffer", "1", true };
-
+cvar_t          scr_viewsize = CVAR3("viewsize","100", true);
+cvar_t          scr_fov = CVAR2("fov","90"); // 10 - 170
+cvar_t          scr_conspeed = CVAR2("scr_conspeed","300");
+cvar_t          scr_centertime = CVAR2("scr_centertime","2");
+cvar_t          scr_showram = CVAR2("showram","1");
+cvar_t          scr_showturtle = CVAR2("showturtle","0");
+cvar_t          scr_showpause = CVAR2("showpause","1");
+cvar_t          scr_printspeed = CVAR2("scr_printspeed","8");
+cvar_t			scr_allowsnap = CVAR2("scr_allowsnap", "1");
+cvar_t			gl_triplebuffer = CVAR3("gl_triplebuffer", "1", true );
 extern	cvar_t	crosshair;
 
 qboolean	scr_initialized;		// ready to draw
@@ -103,7 +103,7 @@
 int			clearconsole;
 int			clearnotify;
 
-int			sb_lines;
+// int			sb_lines;
 
 viddef_t	vid;				// global video state
 
@@ -167,7 +167,7 @@
 
 // the finale prints the characters one at a time
 	if (cl.intermission)
-		remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
+		remaining = (int) (scr_printspeed.value * (cl.time - scr_centertime_start));
 	else
 		remaining = 9999;
 
@@ -175,11 +175,11 @@
 	start = scr_centerstring;
 
 	if (scr_center_lines <= 4)
-		y = vid.height*0.35;
+		y = (int)(vid.height*0.35);
 	else
 		y = 48;
 
-	do	
+	do
 	{
 	// scan the width of the line
 		for (l=0 ; l<40 ; l++)
@@ -188,11 +188,11 @@
 		x = (vid.width - l*8)/2;
 		for (j=0 ; j<l ; j++, x+=8)
 		{
-			Draw_Character (x, y, start[j]);	
+			Draw_Character (x, y, start[j]);
 			if (!remaining--)
 				return;
 		}
-			
+
 		y += 8;
 
 		while (*start && *start != '\n')
@@ -211,7 +211,7 @@
 		scr_erase_lines = scr_center_lines;
 
 	scr_centertime_off -= host_frametime;
-	
+
 	if (scr_centertime_off <= 0 && !cl.intermission)
 		return;
 	if (key_dest != key_game)
@@ -267,7 +267,7 @@
 	Sbar_Changed ();
 
 //========================================
-	
+
 // bound viewsize
 	if (scr_viewsize.value < 30)
 		Cvar_Set ("viewsize","30");
@@ -280,7 +280,7 @@
 	if (scr_fov.value > 170)
 		Cvar_Set ("fov","170");
 
-// intermission is always full screen	
+// intermission is always full screen
 	if (cl.intermission)
 		size = 120;
 	else
@@ -308,22 +308,22 @@
 
 	h = vid.height - sb_lines;
 
-	r_refdef.vrect.width = vid.width * size;
+	r_refdef.vrect.width = (int) (vid.width * size);
 	if (r_refdef.vrect.width < 96)
 	{
 		size = 96.0 / r_refdef.vrect.width;
 		r_refdef.vrect.width = 96;	// min for icons
 	}
 
-	r_refdef.vrect.height = vid.height * size;
-	if (r_refdef.vrect.height > vid.height - sb_lines)
+	r_refdef.vrect.height = (int)(vid.height * size);
+	if ((int)(r_refdef.vrect.height) > (int)(vid.height - sb_lines))
 		r_refdef.vrect.height = vid.height - sb_lines;
-	if (r_refdef.vrect.height > vid.height)
+	if ((int)(r_refdef.vrect.height) > (int)(vid.height))
 			r_refdef.vrect.height = vid.height;
 	r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
 	if (full)
 		r_refdef.vrect.y = 0;
-	else 
+	else
 		r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
 
 	r_refdef.fov_x = scr_fov.value;
@@ -420,7 +420,7 @@
 void SCR_DrawTurtle (void)
 {
 	static int	count;
-	
+
 	if (!scr_showturtle.value)
 		return;
 
@@ -468,7 +468,7 @@
 		return;
 
 	pic = Draw_CachePic ("gfx/pause.lmp");
-	Draw_Pic ( (vid.width - pic->width)/2, 
+	Draw_Pic ( (vid.width - pic->width)/2,
 		(vid.height - 48 - pic->height)/2, pic);
 }
 
@@ -485,9 +485,9 @@
 
 	if (!scr_drawloading)
 		return;
-		
+
 	pic = Draw_CachePic ("gfx/loading.lmp");
-	Draw_Pic ( (vid.width - pic->width)/2, 
+	Draw_Pic ( (vid.width - pic->width)/2,
 		(vid.height - 48 - pic->height)/2, pic);
 }
 
@@ -504,10 +504,10 @@
 void SCR_SetUpToDrawConsole (void)
 {
 	Con_CheckResize ();
-	
+
 	if (scr_drawloading)
 		return;		// never a console with loading plaque
-		
+
 // decide on the height of the console
 	con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
 
@@ -520,7 +520,7 @@
 		scr_conlines = vid.height/2;	// half screen
 	else
 		scr_conlines = 0;				// none visible
-	
+
 	if (scr_conlines < scr_con_current)
 	{
 		scr_con_current -= scr_conspeed.value*host_frametime;
@@ -545,7 +545,7 @@
 	else
 		con_notifylines = 0;
 }
-	
+
 /*
 ==================
 SCR_DrawConsole
@@ -556,7 +556,7 @@
 	if (scr_con_current)
 	{
 		scr_copyeverything = 1;
-		Con_DrawConsole (scr_con_current, true);
+		Con_DrawConsole ((int) scr_con_current, true);
 		clearconsole = 0;
 	}
 	else
@@ -567,13 +567,13 @@
 }
 
 
-/* 
-============================================================================== 
- 
-						SCREEN SHOTS 
- 
-============================================================================== 
-*/ 
+/*
+==============================================================================
+
+						SCREEN SHOTS
+
+==============================================================================
+*/
 
 typedef struct _TargaHeader {
 	unsigned char 	id_length, colormap_type, image_type;
@@ -584,38 +584,38 @@
 } TargaHeader;
 
 
-/* 
-================== 
+/*
+==================
 SCR_ScreenShot_f
-================== 
-*/  
-void SCR_ScreenShot_f (void) 
+==================
+*/
+void SCR_ScreenShot_f (void)
 {
 	byte		*buffer;
-	char		pcxname[80]; 
+	char		pcxname[80];
 	char		checkname[MAX_OSPATH];
 	int			i, c, temp;
-// 
-// find a file name to save it to 
-// 
+//
+// find a file name to save it to
+//
 	strcpy(pcxname,"quake00.tga");
-		
-	for (i=0 ; i<=99 ; i++) 
-	{ 
-		pcxname[5] = i/10 + '0'; 
-		pcxname[6] = i%10 + '0'; 
+
+	for (i=0 ; i<=99 ; i++)
+	{
+		pcxname[5] = i/10 + '0';
+		pcxname[6] = i%10 + '0';
 		sprintf (checkname, "%s/%s", com_gamedir, pcxname);
 		if (Sys_FileTime(checkname) == -1)
 			break;	// file doesn't exist
-	} 
-	if (i==100) 
+	}
+	if (i==100)
 	{
-		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n"); 
+		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n");
 		return;
  	}
 
 
-	buffer = malloc(glwidth*glheight*3 + 18);
+	buffer = (byte*) malloc(glwidth*glheight*3 + 18);
 	memset (buffer, 0, 18);
 	buffer[2] = 2;		// uncompressed type
 	buffer[12] = glwidth&255;
@@ -624,7 +624,7 @@
 	buffer[15] = glheight>>8;
 	buffer[16] = 24;	// pixel size
 
-	glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); 
+	glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
 
 	// swap rgb to bgr
 	c = 18+glwidth*glheight*3;
@@ -638,7 +638,7 @@
 
 	free (buffer);
 	Con_Printf ("Wrote %s\n", pcxname);
-} 
+}
 
 
 //=============================================================================
@@ -658,7 +658,7 @@
 		return;
 	if (cls.signon != SIGNONS)
 		return;
-	
+
 // redraw with no console and the loading plaque
 	Con_ClearNotify ();
 	scr_centertime_off = 0;
@@ -690,21 +690,21 @@
 
 //=============================================================================
 
-char	*scr_notifystring;
+const char	*scr_notifystring;
 qboolean	scr_drawdialog;
 
 void SCR_DrawNotifyString (void)
 {
-	char	*start;
+	const char	*start;
 	int		l;
 	int		j;
 	int		x, y;
 
 	start = scr_notifystring;
 
-	y = vid.height*0.35;
+	y = (int)(vid.height*0.35);
 
-	do	
+	do
 	{
 	// scan the width of the line
 		for (l=0 ; l<40 ; l++)
@@ -712,8 +712,8 @@
 				break;
 		x = (vid.width - l*8)/2;
 		for (j=0 ; j<l ; j++, x+=8)
-			Draw_Character (x, y, start[j]);	
-			
+			Draw_Character (x, y, start[j]);
+
 		y += 8;
 
 		while (*start && *start != '\n')
@@ -730,22 +730,26 @@
 SCR_ModalMessage
 
 Displays a text string in the center of the screen and waits for a Y or N
-keypress.  
+keypress.
 ==================
 */
-int SCR_ModalMessage (char *text)
+int SCR_ModalMessage (const char *text)
 {
 	if (cls.state == ca_dedicated)
 		return true;
 
+#if 1
+	// On Android we can't do modal key events, so just say "yes"
+	return 1;
+#else
 	scr_notifystring = text;
- 
+
 // draw a fresh screen
 	scr_fullupdate = 0;
 	scr_drawdialog = true;
 	SCR_UpdateScreen ();
 	scr_drawdialog = false;
-	
+
 	S_ClearBuffer ();		// so dma doesn't loop current sound
 
 	do
@@ -758,6 +762,7 @@
 	SCR_UpdateScreen ();
 
 	return key_lastpress == 'y';
+#endif
 }
 
 
@@ -773,9 +778,9 @@
 void SCR_BringDownConsole (void)
 {
 	int		i;
-	
+
 	scr_centertime_off = 0;
-	
+
 	for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
 		SCR_UpdateScreen ();
 
@@ -789,20 +794,20 @@
 		// left
 		Draw_TileClear (0, 0, r_refdef.vrect.x, vid.height - sb_lines);
 		// right
-		Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0, 
-			vid.width - r_refdef.vrect.x + r_refdef.vrect.width, 
+		Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0,
+			vid.width - r_refdef.vrect.x + r_refdef.vrect.width,
 			vid.height - sb_lines);
 	}
 	if (r_refdef.vrect.y > 0) {
 		// top
-		Draw_TileClear (r_refdef.vrect.x, 0, 
-			r_refdef.vrect.x + r_refdef.vrect.width, 
+		Draw_TileClear (r_refdef.vrect.x, 0,
+			r_refdef.vrect.x + r_refdef.vrect.width,
 			r_refdef.vrect.y);
 		// bottom
 		Draw_TileClear (r_refdef.vrect.x,
-			r_refdef.vrect.y + r_refdef.vrect.height, 
-			r_refdef.vrect.width, 
-			vid.height - sb_lines - 
+			r_refdef.vrect.y + r_refdef.vrect.height,
+			r_refdef.vrect.width,
+			vid.height - sb_lines -
 			(r_refdef.vrect.height + r_refdef.vrect.y));
 	}
 }
@@ -826,7 +831,7 @@
 	if (block_drawing)
 		return;
 
-	vid.numpages = 2 + gl_triplebuffer.value;
+	vid.numpages = (int)(2 + gl_triplebuffer.value);
 
 	scr_copytop = 0;
 	scr_copyeverything = 0;
@@ -847,12 +852,12 @@
 
 
 	GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-	
+
 	//
 	// determine size of refresh window
 	//
 	if (oldfov != scr_fov.value)
-	{

+	{
 		oldfov = scr_fov.value;
 		vid.recalc_refdef = true;
 	}
@@ -870,7 +875,7 @@
 // do 3D refresh drawing, and then update the screen
 //
 	SCR_SetUpToDrawConsole ();
-	
+
 	V_RenderView ();
 
 	GL_Set2D ();
@@ -905,14 +910,14 @@
 	{
 		if (crosshair.value)
 			Draw_Character (scr_vrect.x + scr_vrect.width/2, scr_vrect.y + scr_vrect.height/2, '+');
-		
+
 		SCR_DrawRam ();
 		SCR_DrawNet ();
 		SCR_DrawTurtle ();
 		SCR_DrawPause ();
 		SCR_CheckDrawCenterString ();
 		Sbar_Draw ();
-		SCR_DrawConsole ();	
+		SCR_DrawConsole ();
 		M_Draw ();
 	}
 
@@ -920,4 +925,3 @@
 
 	GL_EndRendering ();
 }
-
diff --git a/quake/src/WinQuake/gl_test.c b/quake/src/WinQuake/gl_test.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/gl_test.c
rename to quake/src/WinQuake/gl_test.cpp
diff --git a/quake/src/WinQuake/gl_vidandroid.cpp b/quake/src/WinQuake/gl_vidandroid.cpp
new file mode 100755
index 0000000..772a906
--- /dev/null
+++ b/quake/src/WinQuake/gl_vidandroid.cpp
@@ -0,0 +1,789 @@
+/*
+Copyright (C) 2007 The Android Open Source Project
+
+*/
+
+#include "quakedef.h"
+
+unsigned short	d_8to16table[256];
+unsigned	d_8to24table[256];
+
+#ifdef SUPPORT_8BIT_MIPMAPGENERATION
+unsigned char d_15to8table[65536];
+#endif
+
+cvar_t  mouse_button_commands[3] =
+{
+    CVAR2("mouse1","+attack"),
+    CVAR2("mouse2","+strafe"),
+    CVAR2("mouse3","+forward"),
+};
+
+static const int MOUSE_LEFTBUTTON = 1;
+static const int MOUSE_MIDDLEBUTTON = 2;
+static const int MOUSE_RIGHTBUTTON = 4;
+
+bool     mouse_tap;
+float   mouse_x, mouse_y;
+float   old_mouse_x, old_mouse_y;
+int     mx, my;
+bool    mouse_buttonstate;
+bool    mouse_oldbuttonstate;
+
+cvar_t  m_filter = CVAR2("m_filter","1");
+
+int scr_width, scr_height;
+
+cvar_t	_windowed_mouse = CVAR3("_windowed_mouse","0", true);
+
+/*-----------------------------------------------------------------------*/
+
+//int		texture_mode = GL_NEAREST;
+//int		texture_mode = GL_NEAREST_MIPMAP_NEAREST;
+//int		texture_mode = GL_NEAREST_MIPMAP_LINEAR;
+int		texture_mode = GL_LINEAR;
+// int		texture_mode = GL_LINEAR_MIPMAP_NEAREST;
+//int		texture_mode = GL_LINEAR_MIPMAP_LINEAR;
+
+int		texture_extension_number = 1;
+
+float		gldepthmin, gldepthmax;
+
+cvar_t	gl_ztrick = CVAR2("gl_ztrick","0");
+
+const char *gl_vendor;
+const char *gl_renderer;
+const char *gl_version;
+const char *gl_extensions;
+
+qboolean is8bit = false;
+qboolean isPermedia = false;
+qboolean gl_mtexable = false;
+
+/*-----------------------------------------------------------------------*/
+void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
+{
+}
+
+void D_EndDirectRect (int x, int y, int width, int height)
+{
+}
+
+void VID_Shutdown(void)
+{
+}
+
+void VID_ShiftPalette(unsigned char *p)
+{
+//	VID_SetPalette(p);
+}
+
+void	VID_SetPalette (unsigned char *palette)
+{
+  byte	*pal;
+  unsigned r,g,b;
+  unsigned v;
+  int     r1,g1,b1;
+  int		k;
+  unsigned short i;
+  unsigned	*table;
+  FILE *f;
+  char s[255];
+  int dist, bestdist;
+  static qboolean palflag = false;
+
+  PMPBEGIN(("VID_SetPalette"));
+//
+// 8 8 8 encoding
+//
+  Con_Printf("Converting 8to24\n");
+
+  pal = palette;
+  table = d_8to24table;
+  for (i=0 ; i<256 ; i++)
+  {
+    r = pal[0];
+    g = pal[1];
+    b = pal[2];
+    pal += 3;
+
+//		v = (255<<24) + (r<<16) + (g<<8) + (b<<0);
+//		v = (255<<0) + (r<<8) + (g<<16) + (b<<24);
+    v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
+    *table++ = v;
+  }
+  d_8to24table[255] &= 0xffffff;	// 255 is transparent
+
+#ifdef SUPPORT_8BIT_MIPMAPGENERATION
+
+  // JACK: 3D distance calcs - k is last closest, l is the distance.
+  // FIXME: Precalculate this and cache to disk.
+  if (palflag)
+    return;
+  palflag = true;
+
+  COM_FOpenFile("glquake/15to8.pal", &f);
+  if (f) {
+    fread(d_15to8table, 1<<15, 1, f);
+    fclose(f);
+  } else {
+    PMPBEGIN(("Creating 15to8 palette"));
+    for (i=0; i < (1<<15); i++) {
+      /* Maps
+       0000.0000.0000.0000
+       0000.0000.0001.1111 = Red   = 0x001F
+       0000.0011.1110.0000 = Green = 0x03E0
+       0111.1100.0000.0000 = Blue  = 0x7C00
+       */
+       r = ((i & 0x1F) << 3)+4;
+       g = ((i & 0x03E0) >> (5-3)) +4;
+       b = ((i & 0x7C00) >> (10-3))+4;
+      pal = (unsigned char *)d_8to24table;
+      for (v=0,k=0,bestdist=0x7FFFFFFF; v<256; v++,pal+=4) {
+         r1 = (int)r - (int)pal[0];
+         g1 = (int)g - (int)pal[1];
+         b1 = (int)b - (int)pal[2];
+        dist = ((r1*r1)+(g1*g1)+(b1*b1));
+        if (dist < bestdist) {
+          k=v;
+          bestdist = dist;
+        }
+      }
+      d_15to8table[i]=k;
+    }
+    PMPEND(("Creating 15to8 palette"));
+    sprintf(s, "%s/glquake", com_gamedir);
+     Sys_mkdir (s);
+    sprintf(s, "%s/glquake/15to8.pal", com_gamedir);
+    if ((f = fopen(s, "wb")) != NULL) {
+      fwrite(d_15to8table, 1<<15, 1, f);
+      fclose(f);
+    }
+    else
+    {
+      Con_Printf("Could not write %s\n", s);
+    }
+  }
+
+#endif // SUPPORT_8BIT_MIPMAPGENERATION
+  PMPEND(("VID_SetPalette"));
+}
+
+/*
+===============
+GL_Init
+===============
+*/
+void GL_Init (void)
+{
+  gl_vendor = (char*) glGetString (GL_VENDOR);
+  Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
+  gl_renderer = (char*) glGetString (GL_RENDERER);
+  Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
+
+  gl_version = (char*) glGetString (GL_VERSION);
+  Con_Printf ("GL_VERSION: %s\n", gl_version);
+  gl_extensions = (char*) glGetString (GL_EXTENSIONS);
+  Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
+
+//	Con_Printf ("%s %s\n", gl_renderer, gl_version);
+
+  // Enable/disable multitexture:
+
+  gl_mtexable = true;
+
+  glClearColor (1,0,0,0);
+  glCullFace(GL_FRONT);
+  glEnable(GL_TEXTURE_2D);
+
+  glEnable(GL_ALPHA_TEST);
+  glAlphaFunc(GL_GREATER, 0.666);
+
+#ifdef USE_OPENGLES
+#else
+  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+#endif
+  glShadeModel(GL_FLAT);
+    glDisable(GL_DITHER);
+
+    // perspective correction don't work well currently
+    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+//	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+#ifdef USE_OPENGLES
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+#endif
+}
+
+/*
+=================
+GL_BeginRendering
+
+=================
+*/
+void GL_BeginRendering (int *x, int *y, int *width, int *height)
+{
+  extern cvar_t gl_clear;
+
+  *x = *y = 0;
+  *width = scr_width;
+  *height = scr_height;
+
+//    if (!wglMakeCurrent( maindc, baseRC ))
+//		Sys_Error ("wglMakeCurrent failed");
+
+//	glViewport (*x, *y, *width, *height);
+}
+
+
+void GL_EndRendering (void)
+{
+  //glFlush();
+  // !!! Swap buffers.
+}
+
+void Init_KBD(void)
+{
+}
+
+// This function controls whether or not 8-bit paletted textures are used:
+
+qboolean VID_Is8bit(void)
+{
+  return 0;
+}
+
+static void Check_Gamma (unsigned char *pal)
+{
+    float vid_gamma;
+  float	f, inf;
+  unsigned char	palette[768];
+  int		i;
+
+  if ((i = COM_CheckParm("-gamma")) == 0) {
+    vid_gamma = 0.5;	// brighten up game.
+  } else
+    vid_gamma = Q_atof(com_argv[i+1]);
+
+  if(vid_gamma != 1)
+  {
+    for (i=0 ; i<768 ; i++)
+    {
+      f = pow ( (pal[i]+1)/256.0 , vid_gamma );
+      inf = f*255 + 0.5;
+      if (inf < 0)
+        inf = 0;
+      if (inf > 255)
+        inf = 255;
+      palette[i] = (unsigned char) inf;
+    }
+  }
+
+  memcpy (pal, palette, sizeof(palette));
+}
+
+void VID_Init(unsigned char *palette)
+{
+  int i;
+  GLint attribs[32];
+  char	gldir[MAX_OSPATH];
+  int width = scr_width, height = scr_height;
+
+  S_Init();
+
+  Init_KBD();
+
+  Cvar_RegisterVariable (&gl_ztrick);
+
+  vid.maxwarpwidth = scr_width;
+  vid.maxwarpheight = height;
+  vid.colormap = host_colormap;
+  vid.fullbright = 0xffff;
+  vid.aspect = (float) scr_width / (float) scr_height;
+  vid.numpages = 2;
+  vid.rowbytes = 2 * scr_width;
+  vid.width = scr_width;
+  vid.height = scr_height;
+
+  vid.conwidth = scr_width;
+  vid.conheight = scr_height;
+
+// interpret command-line params
+
+// set vid parameters
+
+  GL_Init();
+
+  sprintf (gldir, "%s/glquake", com_gamedir);
+  Sys_mkdir (gldir);
+
+  Check_Gamma(palette);
+  VID_SetPalette(palette);
+
+  Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
+
+  vid.recalc_refdef = 1;				// force a surface cache flush
+}
+
+// Android Key event codes. Some of these are
+// only generated from the simulator.
+// Not all Android devices can generate all codes.
+
+byte scantokey[] =
+{
+    '$', K_ESCAPE, '$', '$',  K_ESCAPE, '$', '$', '0', //  0.. 7
+    '1', '2', '3', '4',  '5', '6', '7', '8', //  8..15
+    '9', '$', '$', K_UPARROW,  K_DOWNARROW, K_LEFTARROW, K_RIGHTARROW, K_ENTER, // 16..23
+    '$', '$', '$', '$',  '$', 'a', 'b', 'c', // 24..31
+
+    'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', // 32..39
+    'l', 'm', 'n', 'o',  'p', 'q', 'r', 's', // 40..47
+    't', 'u', 'v', 'w',  'x', 'y', 'z', ',', // 48..55
+    '.', K_CTRL, K_SHIFT, K_TAB,  ' ', '$', '$', '$', // 56..63
+  '$', '$', K_ENTER, K_BACKSPACE, '`', '-',  '=', '[', // 64..71
+  ']', '\\', ';', '\'', '/', '@',  '#', '$', // 72..79
+  '$', '$', K_ESCAPE, '$'                       // 80..83
+};
+
+byte scantokeyAlt[] =
+{
+    0, 0, 0, 0,  0, 0, 0, 0, //  0.. 7
+    0, 0, 0, 0,  0, 0, 0, 0, //  8..15
+    0, 0, 0, 0,  0, 0, 0, 0, // 16..23
+    0, 0, 0, 0,  0, '%', '=', '8', // 24..31
+
+    '5', '2', '6', '-',  '[', '$', ']', '"', // 32..39
+    '\'', '>', '<', '(',  ')', '*', '3', '4', // 40..47
+    '+', '&', '9', '1',  '7', '!', '#', ';', // 48..55
+    ':', 0, 0, 0,  K_TAB, 0, 0, 0, // 56..63
+  0, 0, 0, 0,  0, 0, 0, 0, // 64..71
+  0, 0, '?', '0',  0, 0, 0, 0, // 72..79
+  0, 0, K_ESCAPE, 0                       // 80..83
+};
+
+#if 0
+
+byte scantokeyCap[] =
+{
+    0, 0, 0, 0,  0, 0, 0, 0, //  0.. 7
+    0, 0, 0, 0,  0, 0, 0, 0, //  8..15
+    0, 0, 0, 0,  0, 0, 0, 0, // 16..23
+    0, 0, 0, 0,  0, 'A', 'B', 'C', // 24..31
+
+    'D', 'E', 'F', 'G',  'H', 'I', 'J', 'K', // 32..39
+    'L', 'M', 'N', 'O',  'P', 'Q', 'R', 'S', // 40..47
+    'T', 'U', 'V', 'W',  'X', 'Y', 'Z', 0, // 48..55
+    0, 0, 0, 0,  0, 0, 0, 0, // 56..63
+  0, 0, 0, 0,  0, 0, 0, 0, // 64..71
+  0, 0, 0, 0,  0, 0, 0, 0, // 72..79
+  0, 0, K_ESCAPE, 0                       // 80..83
+};
+
+#endif
+
+byte scantokeySym[] =
+{
+    0, 0, 0, 0,  0, 0, 0, 0, //  0.. 7
+    0, 0, 0, 0,  0, 0, 0, 0, //  8..15
+    0, 0, 0, 0,  0, 0, 0, 0, // 16..23
+    0, 0, 0, 0,  0, 0, 0, K_F8, // 24..31
+
+    K_F5, K_F2, K_F6, '_',  0, 0, 0, 0, // 32..39
+    0, 0, 0, 0,  0, 0, K_F3, K_F4, // 40..47
+    K_F11, 0, K_F9, K_F1,  K_F7, K_F12, K_PAUSE, 0, // 48..55
+    0, 0, 0, 0,  0, 0, 0, 0, // 56..63
+  0, 0, 0, 0,  0, 0, 0, 0, // 64..71
+  0, 0, '`', K_F10,  0, 0, 0, 0, // 72..79
+  0, 0, K_ESCAPE, 0                       // 80..83
+};
+
+#define ALT_KEY_VALUE 57
+// #define CAPS_KEY_VALUE 58
+#define SYM_KEY_VALUE 61
+
+byte modifierKeyInEffect;
+
+qboolean symKeyDown;
+byte symKeyCode;
+
+// Called from stand-alone main() function to process an event.
+// Return non-zero if the event is handled.
+
+int AndroidEvent(int type, int value)
+{
+  if(value >= 0 && value < (int) sizeof(scantokey))
+  {
+    byte key;
+    qboolean isPress = type != 0;
+
+    qboolean isModifier = value == ALT_KEY_VALUE || value == SYM_KEY_VALUE;
+
+    if(isModifier)
+    {
+      if(isPress)
+      {
+        if(modifierKeyInEffect == value)
+        {
+          // Press modifier twice to cancel modifier
+          modifierKeyInEffect = 0;
+        }
+        else
+        {
+          // Most recent modifier key wins
+          modifierKeyInEffect = value;
+        }
+      }
+      return 1;
+    }
+    else
+    {
+      switch(modifierKeyInEffect)
+      {
+        default:	        key = scantokey[value]; break;
+        case ALT_KEY_VALUE: key = scantokeyAlt[value]; break;
+        // case CAP_KEY_VALUE: key = scantokeyCap[value]; break;
+        case SYM_KEY_VALUE: key = scantokeySym[value]; break;
+      }
+      if(!key)
+      {
+        key = scantokey[value];
+      }
+
+      // Hack: Remap @ and / to K_CTRL in game mode
+      if(key_dest == key_game && ! modifierKeyInEffect && (key == '@' || key == '/'))
+      {
+        key = K_CTRL;
+      }
+
+      if(!isPress)
+      {
+        modifierKeyInEffect = 0;
+      }
+    }
+
+    Key_Event(key, type);
+    // PMPLOG(("type: %d, value: %d -> %d '%c'\n", type, value, key, key));
+
+    return 1;
+  }
+  else
+  {
+    PMPWARNING(("unexpected event type: %d, value: %d\n", type, value));
+  }
+  return 0;
+}
+
+// Called from Java to process an event.
+// Return non-zero if the event is handled.
+
+int AndroidEvent2(int type, int value)
+{
+  Key_Event(value, type);
+  return 0;
+}
+
+static const int MOTION_DOWN = 0;
+static const int MOTION_UP = 1;
+static const int MOTION_MOVE = 2;
+static const int MOTION_CANCEL = 3;
+
+class GestureDetector {
+private:
+    bool mIsScroll;
+    bool mIsTap;
+    bool mIsDoubleTap;
+
+    float mScrollX;
+    float mScrollY;
+
+    static const unsigned long long TAP_TIME_MS = 200;
+    static const unsigned long long DOUBLE_TAP_TIME_MS = 400;
+    static const int TAP_REGION_MANHATTAN_DISTANCE = 10;
+
+    bool mAlwaysInTapRegion;
+    float mDownX;
+    float mDownY;
+    unsigned long long mDownTime;
+    unsigned long long mPreviousDownTime;
+
+    /**
+     * Position of the last motion event.
+     */
+    float mLastMotionY;
+    float mLastMotionX;
+
+public:
+    /**
+     * Analyze a motion event. Call this once for each motion event
+     * that is received by a view.
+     * @param ev the motion event to analyze.
+     */
+    void analyze(unsigned long long eventTime, int action,
+            float x, float y, float pressure, float size, int deviceId) {
+        mIsScroll = false;
+        mIsTap = false;
+        mIsDoubleTap = false;
+
+        switch (action) {
+          case MOTION_DOWN:
+            printf("Down");
+            // Remember where the motion event started
+            mLastMotionX = x;
+            mLastMotionY = y;
+            mDownX = x;
+            mDownY = y;
+            mPreviousDownTime = mDownTime;
+            mDownTime = eventTime;
+            mAlwaysInTapRegion = true;
+            break;
+
+          case MOTION_MOVE:
+          {
+            mIsScroll = true;
+            mScrollX = mLastMotionX - x;
+            mScrollY = mLastMotionY - y;
+            mLastMotionX = x;
+            mLastMotionY = y;
+            int manhattanTapDistance = (int) (absf(x - mDownX) +
+                    absf(y - mDownY));
+            if (manhattanTapDistance > TAP_REGION_MANHATTAN_DISTANCE) {
+                mAlwaysInTapRegion = false;
+            }
+          }
+          break;
+
+          case MOTION_UP:
+          {
+              unsigned long long doubleTapDelta =
+                  eventTime - mPreviousDownTime;
+              unsigned long long singleTapDelta =
+                  eventTime - mDownTime;
+
+              if (mAlwaysInTapRegion) {
+                  if (doubleTapDelta < DOUBLE_TAP_TIME_MS) {
+                      mIsDoubleTap = true;
+                  }
+                  else if (singleTapDelta < TAP_TIME_MS) {
+                      mIsTap = true;
+                  }
+              }
+          }
+          break;
+        }
+    }
+
+    /**
+     * @return true if the current motion event is a scroll
+     * event.
+     */
+    bool isScroll() {
+        return mIsScroll;
+    }
+
+    /**
+     * This value is only defined if {@link #isScroll} is true.
+     * @return the X position of the current scroll event.
+     * event.
+     */
+    float scrollX() {
+        return mScrollX;
+    }
+
+    /**
+     * This value is only defined if {@link #isScroll} is true.
+     * @return the Y position of the current scroll event.
+     * event.
+     */
+    float scrollY() {
+        return mScrollY;
+    }
+
+    /**
+     * @return true if the current motion event is a single-tap
+     * event.
+     */
+    bool isTap() {
+        return mIsTap;
+    }
+
+    /**
+     * This value is only defined if either {@link #isTap} or
+     * {@link #isDoubleTap} is true.
+     * @return the X position of the current tap event.
+     * event.
+     */
+    float tapX() {
+        return mDownX;
+    }
+
+    /**
+     * This value is only defined if either {@link #isTap} or
+     * {@link #isDoubleTap} is true.
+     * @return the Y position of the current tap event.
+     * event.
+     */
+    float tapY() {
+        return mDownY;
+    }
+
+    /**
+     * @return true if the current motion event is a double-tap
+     * event.
+     */
+    bool isDoubleTap() {
+        return mIsDoubleTap;
+    }
+
+private:
+    inline float absf(float a) {
+        return a >= 0.0f ? a : -a;
+    }
+};
+
+GestureDetector gGestureDetector;
+
+int AndroidMotionEvent(unsigned long long eventTime, int action,
+        float x, float y, float pressure, float size, int deviceId)
+{
+    gGestureDetector.analyze(eventTime, action, x, y, pressure, size, deviceId);
+
+    if (gGestureDetector.isTap()) {
+        mouse_tap = true;
+    }
+    else if (gGestureDetector.isScroll()) {
+        mx += (int) gGestureDetector.scrollX();
+        my += (int) gGestureDetector.scrollY();
+    }
+
+    return true;
+}
+
+int AndroidTrackballEvent(unsigned long long eventTime, int action,
+        float x, float y)
+{
+    switch (action ) {
+    case MOTION_DOWN:
+      mouse_buttonstate = true;
+      break;
+    case MOTION_UP:
+      mouse_buttonstate = false;
+      break;
+    case MOTION_MOVE:
+      mx += (int) (20.0f * x);
+      my += (int) (20.0f * y);
+      break;
+    }
+
+    return true;
+}
+
+void Sys_SendKeyEvents(void)
+{
+  // Used to poll keyboards on systems that need to poll keyboards.
+}
+
+void Force_CenterView_f (void)
+{
+  cl.viewangles[PITCH] = 0;
+}
+
+void IN_Init(void)
+{
+    Cvar_RegisterVariable (&mouse_button_commands[0]);
+    Cvar_RegisterVariable (&mouse_button_commands[1]);
+    Cvar_RegisterVariable (&mouse_button_commands[2]);
+    Cmd_AddCommand ("force_centerview", Force_CenterView_f);
+
+}
+
+void IN_Shutdown(void)
+{
+}
+
+/*
+===========
+IN_Commands
+===========
+*/
+void IN_Commands (void)
+{
+    // perform button actions
+    if (mouse_tap) {
+        Key_Event (K_MOUSE1, true);
+        Key_Event (K_MOUSE1, false);
+        mouse_tap = false;
+    }
+    if (mouse_buttonstate != mouse_oldbuttonstate) {
+      Key_Event (K_MOUSE1, mouse_buttonstate ? true : false);
+      mouse_oldbuttonstate = mouse_buttonstate;
+    }
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void IN_MouseMove (usercmd_t *cmd)
+{
+#if 0
+    if (m_filter.value)
+    {
+        mouse_x = (mx + old_mouse_x) * 0.5;
+        mouse_y = (my + old_mouse_y) * 0.5;
+    }
+    else
+#endif
+    {
+        mouse_x = mx;
+        mouse_y = my;
+    }
+    old_mouse_x = mx;
+    old_mouse_y = my;
+    mx = my = 0; // clear for next update
+
+    mouse_x *= 5.0f * sensitivity.value;
+    mouse_y *= 5.0f * sensitivity.value;
+
+// add mouse X/Y movement to cmd
+    if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
+        cmd->sidemove += m_side.value * mouse_x;
+    else
+        cl.viewangles[YAW] -= m_yaw.value * mouse_x;
+
+    if (in_mlook.state & 1)
+        V_StopPitchDrift ();
+
+    if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
+    {
+        cl.viewangles[PITCH] += m_pitch.value * mouse_y;
+        if (cl.viewangles[PITCH] > 80)
+            cl.viewangles[PITCH] = 80;
+        if (cl.viewangles[PITCH] < -70)
+            cl.viewangles[PITCH] = -70;
+    }
+    else
+    {
+        if ((in_strafe.state & 1) && noclip_anglehack)
+            cmd->upmove -= m_forward.value * mouse_y;
+        else
+            cmd->forwardmove -= m_forward.value * mouse_y;
+    }
+}
+
+void IN_Move (usercmd_t *cmd)
+{
+  IN_MouseMove(cmd);
+}
+
+
diff --git a/quake/src/WinQuake/gl_vidlinux.c b/quake/src/WinQuake/gl_vidlinux.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/gl_vidlinux.c
rename to quake/src/WinQuake/gl_vidlinux.cpp
diff --git a/quake/src/WinQuake/gl_vidlinuxglx.c b/quake/src/WinQuake/gl_vidlinuxglx.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/gl_vidlinuxglx.c
rename to quake/src/WinQuake/gl_vidlinuxglx.cpp
diff --git a/quake/src/WinQuake/gl_vidnt.c b/quake/src/WinQuake/gl_vidnt.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/gl_vidnt.c
rename to quake/src/WinQuake/gl_vidnt.cpp
diff --git a/quake/src/WinQuake/gl_warp.c b/quake/src/WinQuake/gl_warp.c
deleted file mode 100644
index 33f52a6..0000000
--- a/quake/src/WinQuake/gl_warp.c
+++ /dev/null
@@ -1,1092 +0,0 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// gl_warp.c -- sky and water polygons

-

-#include "quakedef.h"

-

-extern	model_t	*loadmodel;

-

-int		skytexturenum;

-

-int		solidskytexture;

-int		alphaskytexture;

-float	speedscale;		// for top sky and bottom sky

-

-msurface_t	*warpface;

-

-extern cvar_t gl_subdivide_size;

-

-void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)

-{

-	int		i, j;

-	float	*v;

-

-	mins[0] = mins[1] = mins[2] = 9999;

-	maxs[0] = maxs[1] = maxs[2] = -9999;

-	v = verts;

-	for (i=0 ; i<numverts ; i++)

-		for (j=0 ; j<3 ; j++, v++)

-		{

-			if (*v < mins[j])

-				mins[j] = *v;

-			if (*v > maxs[j])

-				maxs[j] = *v;

-		}

-}

-

-void SubdividePolygon (int numverts, float *verts)

-{

-	int		i, j, k;

-	vec3_t	mins, maxs;

-	float	m;

-	float	*v;

-	vec3_t	front[64], back[64];

-	int		f, b;

-	float	dist[64];

-	float	frac;

-	glpoly_t	*poly;

-	float	s, t;

-

-	if (numverts > 60)

-		Sys_Error ("numverts = %i", numverts);

-

-	BoundPoly (numverts, verts, mins, maxs);

-

-	for (i=0 ; i<3 ; i++)

-	{

-		m = (mins[i] + maxs[i]) * 0.5;

-		m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);

-		if (maxs[i] - m < 8)

-			continue;

-		if (m - mins[i] < 8)

-			continue;

-

-		// cut it

-		v = verts + i;

-		for (j=0 ; j<numverts ; j++, v+= 3)

-			dist[j] = *v - m;

-

-		// wrap cases

-		dist[j] = dist[0];

-		v-=i;

-		VectorCopy (verts, v);

-

-		f = b = 0;

-		v = verts;

-		for (j=0 ; j<numverts ; j++, v+= 3)

-		{

-			if (dist[j] >= 0)

-			{

-				VectorCopy (v, front[f]);

-				f++;

-			}

-			if (dist[j] <= 0)

-			{

-				VectorCopy (v, back[b]);

-				b++;

-			}

-			if (dist[j] == 0 || dist[j+1] == 0)

-				continue;

-			if ( (dist[j] > 0) != (dist[j+1] > 0) )

-			{

-				// clip point

-				frac = dist[j] / (dist[j] - dist[j+1]);

-				for (k=0 ; k<3 ; k++)

-					front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);

-				f++;

-				b++;

-			}

-		}

-

-		SubdividePolygon (f, front[0]);

-		SubdividePolygon (b, back[0]);

-		return;

-	}

-

-	poly = Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));

-	poly->next = warpface->polys;

-	warpface->polys = poly;

-	poly->numverts = numverts;

-	for (i=0 ; i<numverts ; i++, verts+= 3)

-	{

-		VectorCopy (verts, poly->verts[i]);

-		s = DotProduct (verts, warpface->texinfo->vecs[0]);

-		t = DotProduct (verts, warpface->texinfo->vecs[1]);

-		poly->verts[i][3] = s;

-		poly->verts[i][4] = t;

-	}

-}

-

-/*

-================

-GL_SubdivideSurface

-

-Breaks a polygon up along axial 64 unit

-boundaries so that turbulent and sky warps

-can be done reasonably.

-================

-*/

-void GL_SubdivideSurface (msurface_t *fa)

-{

-	vec3_t		verts[64];

-	int			numverts;

-	int			i;

-	int			lindex;

-	float		*vec;

-	texture_t	*t;

-

-	warpface = fa;

-

-	//

-	// convert edges back to a normal polygon

-	//

-	numverts = 0;

-	for (i=0 ; i<fa->numedges ; i++)

-	{

-		lindex = loadmodel->surfedges[fa->firstedge + i];

-

-		if (lindex > 0)

-			vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;

-		else

-			vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;

-		VectorCopy (vec, verts[numverts]);

-		numverts++;

-	}

-

-	SubdividePolygon (numverts, verts[0]);

-}

-

-//=========================================================

-

-

-

-// speed up sin calculations - Ed

-float	turbsin[] =

-{

-	#include "gl_warp_sin.h"

-};

-#define TURBSCALE (256.0 / (2 * M_PI))

-

-/*

-=============

-EmitWaterPolys

-

-Does a water warp on the pre-fragmented glpoly_t chain

-=============

-*/

-void EmitWaterPolys (msurface_t *fa)

-{

-	glpoly_t	*p;

-	float		*v;

-	int			i;

-	float		s, t, os, ot;

-

-

-	for (p=fa->polys ; p ; p=p->next)

-	{

-		glBegin (GL_POLYGON);

-		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)

-		{

-			os = v[3];

-			ot = v[4];

-

-			s = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255];

-			s *= (1.0/64);

-

-			t = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255];

-			t *= (1.0/64);

-

-			glTexCoord2f (s, t);

-			glVertex3fv (v);

-		}

-		glEnd ();

-	}

-}

-

-

-

-

-/*

-=============

-EmitSkyPolys

-=============

-*/

-void EmitSkyPolys (msurface_t *fa)

-{

-	glpoly_t	*p;

-	float		*v;

-	int			i;

-	float	s, t;

-	vec3_t	dir;

-	float	length;

-

-	for (p=fa->polys ; p ; p=p->next)

-	{

-		glBegin (GL_POLYGON);

-		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)

-		{

-			VectorSubtract (v, r_origin, dir);

-			dir[2] *= 3;	// flatten the sphere

-

-			length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];

-			length = sqrt (length);

-			length = 6*63/length;

-

-			dir[0] *= length;

-			dir[1] *= length;

-

-			s = (speedscale + dir[0]) * (1.0/128);

-			t = (speedscale + dir[1]) * (1.0/128);

-

-			glTexCoord2f (s, t);

-			glVertex3fv (v);

-		}

-		glEnd ();

-	}

-}

-

-/*

-===============

-EmitBothSkyLayers

-

-Does a sky warp on the pre-fragmented glpoly_t chain

-This will be called for brushmodels, the world

-will have them chained together.

-===============

-*/

-void EmitBothSkyLayers (msurface_t *fa)

-{

-	int			i;

-	int			lindex;

-	float		*vec;

-

-	GL_DisableMultitexture();

-

-	GL_Bind (solidskytexture);

-	speedscale = realtime*8;

-	speedscale -= (int)speedscale & ~127 ;

-

-	EmitSkyPolys (fa);

-

-	glEnable (GL_BLEND);

-	GL_Bind (alphaskytexture);

-	speedscale = realtime*16;

-	speedscale -= (int)speedscale & ~127 ;

-

-	EmitSkyPolys (fa);

-

-	glDisable (GL_BLEND);

-}

-

-#ifndef QUAKE2

-/*

-=================

-R_DrawSkyChain

-=================

-*/

-void R_DrawSkyChain (msurface_t *s)

-{

-	msurface_t	*fa;

-

-	GL_DisableMultitexture();

-

-	// used when gl_texsort is on

-	GL_Bind(solidskytexture);

-	speedscale = realtime*8;

-	speedscale -= (int)speedscale & ~127 ;

-

-	for (fa=s ; fa ; fa=fa->texturechain)

-		EmitSkyPolys (fa);

-

-	glEnable (GL_BLEND);

-	GL_Bind (alphaskytexture);

-	speedscale = realtime*16;

-	speedscale -= (int)speedscale & ~127 ;

-

-	for (fa=s ; fa ; fa=fa->texturechain)

-		EmitSkyPolys (fa);

-

-	glDisable (GL_BLEND);

-}

-

-#endif

-

-/*

-=================================================================

-

-  Quake 2 environment sky

-

-=================================================================

-*/

-

-#ifdef QUAKE2

-

-

-#define	SKY_TEX		2000

-

-/*

-=================================================================

-

-  PCX Loading

-

-=================================================================

-*/

-

-typedef struct

-{

-    char	manufacturer;

-    char	version;

-    char	encoding;

-    char	bits_per_pixel;

-    unsigned short	xmin,ymin,xmax,ymax;

-    unsigned short	hres,vres;

-    unsigned char	palette[48];

-    char	reserved;

-    char	color_planes;

-    unsigned short	bytes_per_line;

-    unsigned short	palette_type;

-    char	filler[58];

-    unsigned 	data;			// unbounded

-} pcx_t;

-

-byte	*pcx_rgb;

-

-/*

-============

-LoadPCX

-============

-*/

-void LoadPCX (FILE *f)

-{

-	pcx_t	*pcx, pcxbuf;

-	byte	palette[768];

-	byte	*pix;

-	int		x, y;

-	int		dataByte, runLength;

-	int		count;

-

-//

-// parse the PCX file

-//

-	fread (&pcxbuf, 1, sizeof(pcxbuf), f);

-

-	pcx = &pcxbuf;

-

-	if (pcx->manufacturer != 0x0a

-		|| pcx->version != 5

-		|| pcx->encoding != 1

-		|| pcx->bits_per_pixel != 8

-		|| pcx->xmax >= 320

-		|| pcx->ymax >= 256)

-	{

-		Con_Printf ("Bad pcx file\n");

-		return;

-	}

-

-	// seek to palette

-	fseek (f, -768, SEEK_END);

-	fread (palette, 1, 768, f);

-

-	fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);

-

-	count = (pcx->xmax+1) * (pcx->ymax+1);

-	pcx_rgb = malloc( count * 4);

-

-	for (y=0 ; y<=pcx->ymax ; y++)

-	{

-		pix = pcx_rgb + 4*y*(pcx->xmax+1);

-		for (x=0 ; x<=pcx->ymax ; )

-		{

-			dataByte = fgetc(f);

-

-			if((dataByte & 0xC0) == 0xC0)

-			{

-				runLength = dataByte & 0x3F;

-				dataByte = fgetc(f);

-			}

-			else

-				runLength = 1;

-

-			while(runLength-- > 0)

-			{

-				pix[0] = palette[dataByte*3];

-				pix[1] = palette[dataByte*3+1];

-				pix[2] = palette[dataByte*3+2];

-				pix[3] = 255;

-				pix += 4;

-				x++;

-			}

-		}

-	}

-}

-

-/*

-=========================================================

-

-TARGA LOADING

-

-=========================================================

-*/

-

-typedef struct _TargaHeader {

-	unsigned char 	id_length, colormap_type, image_type;

-	unsigned short	colormap_index, colormap_length;

-	unsigned char	colormap_size;

-	unsigned short	x_origin, y_origin, width, height;

-	unsigned char	pixel_size, attributes;

-} TargaHeader;

-

-

-TargaHeader		targa_header;

-byte			*targa_rgba;

-

-int fgetLittleShort (FILE *f)

-{

-	byte	b1, b2;

-

-	b1 = fgetc(f);

-	b2 = fgetc(f);

-

-	return (short)(b1 + b2*256);

-}

-

-int fgetLittleLong (FILE *f)

-{

-	byte	b1, b2, b3, b4;

-

-	b1 = fgetc(f);

-	b2 = fgetc(f);

-	b3 = fgetc(f);

-	b4 = fgetc(f);

-

-	return b1 + (b2<<8) + (b3<<16) + (b4<<24);

-}

-

-

-/*

-=============

-LoadTGA

-=============

-*/

-void LoadTGA (FILE *fin)

-{

-	int				columns, rows, numPixels;

-	byte			*pixbuf;

-	int				row, column;

-

-	targa_header.id_length = fgetc(fin);

-	targa_header.colormap_type = fgetc(fin);

-	targa_header.image_type = fgetc(fin);

-	

-	targa_header.colormap_index = fgetLittleShort(fin);

-	targa_header.colormap_length = fgetLittleShort(fin);

-	targa_header.colormap_size = fgetc(fin);

-	targa_header.x_origin = fgetLittleShort(fin);

-	targa_header.y_origin = fgetLittleShort(fin);

-	targa_header.width = fgetLittleShort(fin);

-	targa_header.height = fgetLittleShort(fin);

-	targa_header.pixel_size = fgetc(fin);

-	targa_header.attributes = fgetc(fin);

-

-	if (targa_header.image_type!=2 

-		&& targa_header.image_type!=10) 

-		Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");

-

-	if (targa_header.colormap_type !=0 

-		|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))

-		Sys_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");

-

-	columns = targa_header.width;

-	rows = targa_header.height;

-	numPixels = columns * rows;

-

-	targa_rgba = malloc (numPixels*4);

-	

-	if (targa_header.id_length != 0)

-		fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment

-	

-	if (targa_header.image_type==2) {  // Uncompressed, RGB images

-		for(row=rows-1; row>=0; row--) {

-			pixbuf = targa_rgba + row*columns*4;

-			for(column=0; column<columns; column++) {

-				unsigned char red,green,blue,alphabyte;

-				switch (targa_header.pixel_size) {

-					case 24:

-							

-							blue = getc(fin);

-							green = getc(fin);

-							red = getc(fin);

-							*pixbuf++ = red;

-							*pixbuf++ = green;

-							*pixbuf++ = blue;

-							*pixbuf++ = 255;

-							break;

-					case 32:

-							blue = getc(fin);

-							green = getc(fin);

-							red = getc(fin);

-							alphabyte = getc(fin);

-							*pixbuf++ = red;

-							*pixbuf++ = green;

-							*pixbuf++ = blue;

-							*pixbuf++ = alphabyte;

-							break;

-				}

-			}

-		}

-	}

-	else if (targa_header.image_type==10) {   // Runlength encoded RGB images

-		unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;

-		for(row=rows-1; row>=0; row--) {

-			pixbuf = targa_rgba + row*columns*4;

-			for(column=0; column<columns; ) {

-				packetHeader=getc(fin);

-				packetSize = 1 + (packetHeader & 0x7f);

-				if (packetHeader & 0x80) {        // run-length packet

-					switch (targa_header.pixel_size) {

-						case 24:

-								blue = getc(fin);

-								green = getc(fin);

-								red = getc(fin);

-								alphabyte = 255;

-								break;

-						case 32:

-								blue = getc(fin);

-								green = getc(fin);

-								red = getc(fin);

-								alphabyte = getc(fin);

-								break;

-					}

-	

-					for(j=0;j<packetSize;j++) {

-						*pixbuf++=red;

-						*pixbuf++=green;

-						*pixbuf++=blue;

-						*pixbuf++=alphabyte;

-						column++;

-						if (column==columns) { // run spans across rows

-							column=0;

-							if (row>0)

-								row--;

-							else

-								goto breakOut;

-							pixbuf = targa_rgba + row*columns*4;

-						}

-					}

-				}

-				else {                            // non run-length packet

-					for(j=0;j<packetSize;j++) {

-						switch (targa_header.pixel_size) {

-							case 24:

-									blue = getc(fin);

-									green = getc(fin);

-									red = getc(fin);

-									*pixbuf++ = red;

-									*pixbuf++ = green;

-									*pixbuf++ = blue;

-									*pixbuf++ = 255;

-									break;

-							case 32:

-									blue = getc(fin);

-									green = getc(fin);

-									red = getc(fin);

-									alphabyte = getc(fin);

-									*pixbuf++ = red;

-									*pixbuf++ = green;

-									*pixbuf++ = blue;

-									*pixbuf++ = alphabyte;

-									break;

-						}

-						column++;

-						if (column==columns) { // pixel packet run spans across rows

-							column=0;

-							if (row>0)

-								row--;

-							else

-								goto breakOut;

-							pixbuf = targa_rgba + row*columns*4;

-						}						

-					}

-				}

-			}

-			breakOut:;

-		}

-	}

-	

-	fclose(fin);

-}

-

-/*

-==================

-R_LoadSkys

-==================

-*/

-char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};

-void R_LoadSkys (void)

-{

-	int		i;

-	FILE	*f;

-	char	name[64];

-

-	for (i=0 ; i<6 ; i++)

-	{

-		GL_Bind (SKY_TEX + i);

-		sprintf (name, "gfx/env/bkgtst%s.tga", suf[i]);

-		COM_FOpenFile (name, &f);

-		if (!f)

-		{

-			Con_Printf ("Couldn't load %s\n", name);

-			continue;

-		}

-		LoadTGA (f);

-//		LoadPCX (f);

-

-		glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, targa_rgba);

-//		glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pcx_rgb);

-

-		free (targa_rgba);

-//		free (pcx_rgb);

-

-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

-		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

-	}

-}

-

-

-vec3_t	skyclip[6] = {

-	{1,1,0},

-	{1,-1,0},

-	{0,-1,1},

-	{0,1,1},

-	{1,0,1},

-	{-1,0,1} 

-};

-int	c_sky;

-

-// 1 = s, 2 = t, 3 = 2048

-int	st_to_vec[6][3] =

-{

-	{3,-1,2},

-	{-3,1,2},

-

-	{1,3,2},

-	{-1,-3,2},

-

-	{-2,-1,3},		// 0 degrees yaw, look straight up

-	{2,-1,-3}		// look straight down

-

-//	{-1,2,3},

-//	{1,2,-3}

-};

-

-// s = [0]/[2], t = [1]/[2]

-int	vec_to_st[6][3] =

-{

-	{-2,3,1},

-	{2,3,-1},

-

-	{1,3,2},

-	{-1,3,-2},

-

-	{-2,-1,3},

-	{-2,1,-3}

-

-//	{-1,2,3},

-//	{1,2,-3}

-};

-

-float	skymins[2][6], skymaxs[2][6];

-

-void DrawSkyPolygon (int nump, vec3_t vecs)

-{

-	int		i,j;

-	vec3_t	v, av;

-	float	s, t, dv;

-	int		axis;

-	float	*vp;

-

-	c_sky++;

-#if 0

-glBegin (GL_POLYGON);

-for (i=0 ; i<nump ; i++, vecs+=3)

-{

-	VectorAdd(vecs, r_origin, v);

-	glVertex3fv (v);

-}

-glEnd();

-return;

-#endif

-	// decide which face it maps to

-	VectorCopy (vec3_origin, v);

-	for (i=0, vp=vecs ; i<nump ; i++, vp+=3)

-	{

-		VectorAdd (vp, v, v);

-	}

-	av[0] = fabs(v[0]);

-	av[1] = fabs(v[1]);

-	av[2] = fabs(v[2]);

-	if (av[0] > av[1] && av[0] > av[2])

-	{

-		if (v[0] < 0)

-			axis = 1;

-		else

-			axis = 0;

-	}

-	else if (av[1] > av[2] && av[1] > av[0])

-	{

-		if (v[1] < 0)

-			axis = 3;

-		else

-			axis = 2;

-	}

-	else

-	{

-		if (v[2] < 0)

-			axis = 5;

-		else

-			axis = 4;

-	}

-

-	// project new texture coords

-	for (i=0 ; i<nump ; i++, vecs+=3)

-	{

-		j = vec_to_st[axis][2];

-		if (j > 0)

-			dv = vecs[j - 1];

-		else

-			dv = -vecs[-j - 1];

-

-		j = vec_to_st[axis][0];

-		if (j < 0)

-			s = -vecs[-j -1] / dv;

-		else

-			s = vecs[j-1] / dv;

-		j = vec_to_st[axis][1];

-		if (j < 0)

-			t = -vecs[-j -1] / dv;

-		else

-			t = vecs[j-1] / dv;

-

-		if (s < skymins[0][axis])

-			skymins[0][axis] = s;

-		if (t < skymins[1][axis])

-			skymins[1][axis] = t;

-		if (s > skymaxs[0][axis])

-			skymaxs[0][axis] = s;

-		if (t > skymaxs[1][axis])

-			skymaxs[1][axis] = t;

-	}

-}

-

-#define	MAX_CLIP_VERTS	64

-void ClipSkyPolygon (int nump, vec3_t vecs, int stage)

-{

-	float	*norm;

-	float	*v;

-	qboolean	front, back;

-	float	d, e;

-	float	dists[MAX_CLIP_VERTS];

-	int		sides[MAX_CLIP_VERTS];

-	vec3_t	newv[2][MAX_CLIP_VERTS];

-	int		newc[2];

-	int		i, j;

-

-	if (nump > MAX_CLIP_VERTS-2)

-		Sys_Error ("ClipSkyPolygon: MAX_CLIP_VERTS");

-	if (stage == 6)

-	{	// fully clipped, so draw it

-		DrawSkyPolygon (nump, vecs);

-		return;

-	}

-

-	front = back = false;

-	norm = skyclip[stage];

-	for (i=0, v = vecs ; i<nump ; i++, v+=3)

-	{

-		d = DotProduct (v, norm);

-		if (d > ON_EPSILON)

-		{

-			front = true;

-			sides[i] = SIDE_FRONT;

-		}

-		else if (d < ON_EPSILON)

-		{

-			back = true;

-			sides[i] = SIDE_BACK;

-		}

-		else

-			sides[i] = SIDE_ON;

-		dists[i] = d;

-	}

-

-	if (!front || !back)

-	{	// not clipped

-		ClipSkyPolygon (nump, vecs, stage+1);

-		return;

-	}

-

-	// clip it

-	sides[i] = sides[0];

-	dists[i] = dists[0];

-	VectorCopy (vecs, (vecs+(i*3)) );

-	newc[0] = newc[1] = 0;

-

-	for (i=0, v = vecs ; i<nump ; i++, v+=3)

-	{

-		switch (sides[i])

-		{

-		case SIDE_FRONT:

-			VectorCopy (v, newv[0][newc[0]]);

-			newc[0]++;

-			break;

-		case SIDE_BACK:

-			VectorCopy (v, newv[1][newc[1]]);

-			newc[1]++;

-			break;

-		case SIDE_ON:

-			VectorCopy (v, newv[0][newc[0]]);

-			newc[0]++;

-			VectorCopy (v, newv[1][newc[1]]);

-			newc[1]++;

-			break;

-		}

-

-		if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])

-			continue;

-

-		d = dists[i] / (dists[i] - dists[i+1]);

-		for (j=0 ; j<3 ; j++)

-		{

-			e = v[j] + d*(v[j+3] - v[j]);

-			newv[0][newc[0]][j] = e;

-			newv[1][newc[1]][j] = e;

-		}

-		newc[0]++;

-		newc[1]++;

-	}

-

-	// continue

-	ClipSkyPolygon (newc[0], newv[0][0], stage+1);

-	ClipSkyPolygon (newc[1], newv[1][0], stage+1);

-}

-

-/*

-=================

-R_DrawSkyChain

-=================

-*/

-void R_DrawSkyChain (msurface_t *s)

-{

-	msurface_t	*fa;

-

-	int		i;

-	vec3_t	verts[MAX_CLIP_VERTS];

-	glpoly_t	*p;

-

-	c_sky = 0;

-	GL_Bind(solidskytexture);

-

-	// calculate vertex values for sky box

-

-	for (fa=s ; fa ; fa=fa->texturechain)

-	{

-		for (p=fa->polys ; p ; p=p->next)

-		{

-			for (i=0 ; i<p->numverts ; i++)

-			{

-				VectorSubtract (p->verts[i], r_origin, verts[i]);

-			}

-			ClipSkyPolygon (p->numverts, verts[0], 0);

-		}

-	}

-}

-

-

-/*

-==============

-R_ClearSkyBox

-==============

-*/

-void R_ClearSkyBox (void)

-{

-	int		i;

-

-	for (i=0 ; i<6 ; i++)

-	{

-		skymins[0][i] = skymins[1][i] = 9999;

-		skymaxs[0][i] = skymaxs[1][i] = -9999;

-	}

-}

-

-

-void MakeSkyVec (float s, float t, int axis)

-{

-	vec3_t		v, b;

-	int			j, k;

-

-	b[0] = s*2048;

-	b[1] = t*2048;

-	b[2] = 2048;

-

-	for (j=0 ; j<3 ; j++)

-	{

-		k = st_to_vec[axis][j];

-		if (k < 0)

-			v[j] = -b[-k - 1];

-		else

-			v[j] = b[k - 1];

-		v[j] += r_origin[j];

-	}

-

-	// avoid bilerp seam

-	s = (s+1)*0.5;

-	t = (t+1)*0.5;

-

-	if (s < 1.0/512)

-		s = 1.0/512;

-	else if (s > 511.0/512)

-		s = 511.0/512;

-	if (t < 1.0/512)

-		t = 1.0/512;

-	else if (t > 511.0/512)

-		t = 511.0/512;

-

-	t = 1.0 - t;

-	glTexCoord2f (s, t);

-	glVertex3fv (v);

-}

-

-/*

-==============

-R_DrawSkyBox

-==============

-*/

-int	skytexorder[6] = {0,2,1,3,4,5};

-void R_DrawSkyBox (void)

-{

-	int		i, j, k;

-	vec3_t	v;

-	float	s, t;

-

-#if 0

-glEnable (GL_BLEND);

-glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

-glColor4f (1,1,1,0.5);

-glDisable (GL_DEPTH_TEST);

-#endif

-	for (i=0 ; i<6 ; i++)

-	{

-		if (skymins[0][i] >= skymaxs[0][i]

-		|| skymins[1][i] >= skymaxs[1][i])

-			continue;

-

-		GL_Bind (SKY_TEX+skytexorder[i]);

-#if 0

-skymins[0][i] = -1;

-skymins[1][i] = -1;

-skymaxs[0][i] = 1;

-skymaxs[1][i] = 1;

-#endif

-		glBegin (GL_QUADS);

-		MakeSkyVec (skymins[0][i], skymins[1][i], i);

-		MakeSkyVec (skymins[0][i], skymaxs[1][i], i);

-		MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i);

-		MakeSkyVec (skymaxs[0][i], skymins[1][i], i);

-		glEnd ();

-	}

-#if 0

-glDisable (GL_BLEND);

-glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

-glColor4f (1,1,1,0.5);

-glEnable (GL_DEPTH_TEST);

-#endif

-}

-

-

-#endif

-

-//===============================================================

-

-/*

-=============

-R_InitSky

-

-A sky texture is 256*128, with the right side being a masked overlay

-==============

-*/

-void R_InitSky (texture_t *mt)

-{

-	int			i, j, p;

-	byte		*src;

-	unsigned	trans[128*128];

-	unsigned	transpix;

-	int			r, g, b;

-	unsigned	*rgba;

-	extern	int			skytexturenum;

-

-	src = (byte *)mt + mt->offsets[0];

-

-	// make an average value for the back to avoid

-	// a fringe on the top level

-

-	r = g = b = 0;

-	for (i=0 ; i<128 ; i++)

-		for (j=0 ; j<128 ; j++)

-		{

-			p = src[i*256 + j + 128];

-			rgba = &d_8to24table[p];

-			trans[(i*128) + j] = *rgba;

-			r += ((byte *)rgba)[0];

-			g += ((byte *)rgba)[1];

-			b += ((byte *)rgba)[2];

-		}

-

-	((byte *)&transpix)[0] = r/(128*128);

-	((byte *)&transpix)[1] = g/(128*128);

-	((byte *)&transpix)[2] = b/(128*128);

-	((byte *)&transpix)[3] = 0;

-

-

-	if (!solidskytexture)

-		solidskytexture = texture_extension_number++;

-	GL_Bind (solidskytexture );

-	glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

-

-

-	for (i=0 ; i<128 ; i++)

-		for (j=0 ; j<128 ; j++)

-		{

-			p = src[i*256 + j];

-			if (p == 0)

-				trans[(i*128) + j] = transpix;

-			else

-				trans[(i*128) + j] = d_8to24table[p];

-		}

-

-	if (!alphaskytexture)

-		alphaskytexture = texture_extension_number++;

-	GL_Bind(alphaskytexture);

-	glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

-}

-

diff --git a/quake/src/WinQuake/gl_warp.cpp b/quake/src/WinQuake/gl_warp.cpp
new file mode 100755
index 0000000..5c016d8
--- /dev/null
+++ b/quake/src/WinQuake/gl_warp.cpp
@@ -0,0 +1,1153 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// gl_warp.c -- sky and water polygons
+
+#include "quakedef.h"
+
+extern  model_t *loadmodel;
+
+//int       skytexturenum;
+
+int     solidskytexture;
+int     alphaskytexture;
+float   speedscale;     // for top sky and bottom sky
+
+msurface_t  *warpface;
+
+extern cvar_t gl_subdivide_size;
+
+void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
+{
+    int     i, j;
+    float   *v;
+
+    mins[0] = mins[1] = mins[2] = 9999;
+    maxs[0] = maxs[1] = maxs[2] = -9999;
+    v = verts;
+    for (i=0 ; i<numverts ; i++)
+        for (j=0 ; j<3 ; j++, v++)
+        {
+            if (*v < mins[j])
+                mins[j] = *v;
+            if (*v > maxs[j])
+                maxs[j] = *v;
+        }
+}
+
+void SubdividePolygon (int numverts, float *verts)
+{
+    int     i, j, k;
+    vec3_t  mins, maxs;
+    float   m;
+    float   *v;
+    vec3_t  front[64], back[64];
+    int     f, b;
+    float   dist[64];
+    float   frac;
+    glpoly_t    *poly;
+    float   s, t;
+
+    if (numverts > 60)
+        Sys_Error ("numverts = %i", numverts);
+
+    BoundPoly (numverts, verts, mins, maxs);
+
+    for (i=0 ; i<3 ; i++)
+    {
+        m = (mins[i] + maxs[i]) * 0.5;
+        m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);
+        if (maxs[i] - m < 8)
+            continue;
+        if (m - mins[i] < 8)
+            continue;
+
+        // cut it
+        v = verts + i;
+        for (j=0 ; j<numverts ; j++, v+= 3)
+            dist[j] = *v - m;
+
+        // wrap cases
+        dist[j] = dist[0];
+        v-=i;
+        VectorCopy (verts, v);
+
+        f = b = 0;
+        v = verts;
+        for (j=0 ; j<numverts ; j++, v+= 3)
+        {
+            if (dist[j] >= 0)
+            {
+                VectorCopy (v, front[f]);
+                f++;
+            }
+            if (dist[j] <= 0)
+            {
+                VectorCopy (v, back[b]);
+                b++;
+            }
+            if (dist[j] == 0 || dist[j+1] == 0)
+                continue;
+            if ( (dist[j] > 0) != (dist[j+1] > 0) )
+            {
+                // clip point
+                frac = dist[j] / (dist[j] - dist[j+1]);
+                for (k=0 ; k<3 ; k++)
+                    front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);
+                f++;
+                b++;
+            }
+        }
+
+        SubdividePolygon (f, front[0]);
+        SubdividePolygon (b, back[0]);
+        return;
+    }
+
+    poly = (glpoly_t*) Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));
+    poly->next = warpface->polys;
+    warpface->polys = poly;
+    poly->numverts = numverts;
+    for (i=0 ; i<numverts ; i++, verts+= 3)
+    {
+        VectorCopy (verts, poly->verts[i]);
+        s = DotProduct (verts, warpface->texinfo->vecs[0]);
+        t = DotProduct (verts, warpface->texinfo->vecs[1]);
+        poly->verts[i][3] = s;
+        poly->verts[i][4] = t;
+    }
+}
+
+/*
+================
+GL_SubdivideSurface
+
+Breaks a polygon up along axial 64 unit
+boundaries so that turbulent and sky warps
+can be done reasonably.
+================
+*/
+void GL_SubdivideSurface (msurface_t *fa)
+{
+    vec3_t      verts[64];
+    int         numverts;
+    int         i;
+    int         lindex;
+    float       *vec;
+    texture_t   *t;
+
+    warpface = fa;
+
+    //
+    // convert edges back to a normal polygon
+    //
+    numverts = 0;
+    for (i=0 ; i<fa->numedges ; i++)
+    {
+        lindex = loadmodel->surfedges[fa->firstedge + i];
+
+        if (lindex > 0)
+            vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
+        else
+            vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
+        VectorCopy (vec, verts[numverts]);
+        numverts++;
+    }
+
+    SubdividePolygon (numverts, verts[0]);
+}
+
+//=========================================================
+
+
+
+// speed up sin calculations - Ed
+float   turbsin[] =
+{
+    #include "gl_warp_sin.h"
+};
+#define TURBSCALE (256.0 / (2 * M_PI))
+
+/*
+=============
+EmitWaterPolys
+
+Does a water warp on the pre-fragmented glpoly_t chain
+=============
+*/
+void EmitWaterPolys (msurface_t *fa)
+{
+    glpoly_t    *p;
+    float       *v;
+    int         i;
+    float       s, t, os, ot;
+
+
+    for (p=fa->polys ; p ; p=p->next)
+    {
+#ifdef USE_OPENGLES 
+        {
+            float* pUV = gTexCoordBuffer;
+            for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
+            {
+                os = v[3];
+                ot = v[4];
+
+                s = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255];
+                s *= (1.0/64);
+
+                t = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255];
+                t *= (1.0/64);
+
+                *pUV++ = s;
+                *pUV++ = t;
+            }
+        }
+        
+        glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
+        glTexCoordPointer(2, GL_FLOAT, 0, gTexCoordBuffer);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+#else
+        glBegin (GL_POLYGON);
+        for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
+        {
+            os = v[3];
+            ot = v[4];
+
+            s = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255];
+            s *= (1.0/64);
+
+            t = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255];
+            t *= (1.0/64);
+
+            glTexCoord2f (s, t);
+            glVertex3fv (v);
+        }
+        glEnd ();
+#endif
+    }
+}
+
+
+
+
+/*
+=============
+EmitSkyPolys
+=============
+*/
+void EmitSkyPolys (msurface_t *fa)
+{
+    glpoly_t    *p;
+    float       *v;
+    int         i;
+    float   s, t;
+    vec3_t  dir;
+    float   length;
+
+    for (p=fa->polys ; p ; p=p->next)
+    {
+#ifdef USE_OPENGLES
+        {
+            float* pUV = gTexCoordBuffer;
+            for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
+            {
+                VectorSubtract (v, r_origin, dir);
+                dir[2] *= 3;    // flatten the sphere
+
+                length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
+                length = sqrt (length);
+                length = 6*63/length;
+
+                dir[0] *= length;
+                dir[1] *= length;
+
+                s = (speedscale + dir[0]) * (1.0/128);
+                t = (speedscale + dir[1]) * (1.0/128);
+
+                *pUV++ = s;
+                *pUV++ = t;
+            }
+        }
+        
+        glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
+        glTexCoordPointer(2, GL_FLOAT, 0, gTexCoordBuffer);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
+#else
+        glBegin (GL_POLYGON);
+        for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
+        {
+            VectorSubtract (v, r_origin, dir);
+            dir[2] *= 3;    // flatten the sphere
+
+            length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
+            length = sqrt (length);
+            length = 6*63/length;
+
+            dir[0] *= length;
+            dir[1] *= length;
+
+            s = (speedscale + dir[0]) * (1.0/128);
+            t = (speedscale + dir[1]) * (1.0/128);
+
+            glTexCoord2f (s, t);
+            glVertex3fv (v);
+        }
+        glEnd ();
+#endif
+    }
+}
+
+/*
+===============
+EmitBothSkyLayers
+
+Does a sky warp on the pre-fragmented glpoly_t chain
+This will be called for brushmodels, the world
+will have them chained together.
+===============
+*/
+void EmitBothSkyLayers (msurface_t *fa)
+{
+    int         i;
+    int         lindex;
+    float       *vec;
+
+    GL_DisableMultitexture();
+
+    GL_Bind (solidskytexture);
+    speedscale = realtime*8;
+    speedscale -= (int)speedscale & ~127 ;
+
+    EmitSkyPolys (fa);
+
+    glEnable (GL_BLEND);
+    GL_Bind (alphaskytexture);
+    speedscale = realtime*16;
+    speedscale -= (int)speedscale & ~127 ;
+
+    EmitSkyPolys (fa);
+
+    glDisable (GL_BLEND);
+}
+
+#ifndef QUAKE2
+/*
+=================
+R_DrawSkyChain
+=================
+*/
+void R_DrawSkyChain (msurface_t *s)
+{
+    msurface_t  *fa;
+
+    GL_DisableMultitexture();
+
+    // used when gl_texsort is on
+    GL_Bind(solidskytexture);
+    speedscale = realtime*8;
+    speedscale -= (int)speedscale & ~127 ;
+
+    for (fa=s ; fa ; fa=fa->texturechain)
+        EmitSkyPolys (fa);
+
+    glEnable (GL_BLEND);
+    GL_Bind (alphaskytexture);
+    speedscale = realtime*16;
+    speedscale -= (int)speedscale & ~127 ;
+
+    for (fa=s ; fa ; fa=fa->texturechain)
+        EmitSkyPolys (fa);
+
+    glDisable (GL_BLEND);
+}
+
+#endif
+
+/*
+=================================================================
+
+  Quake 2 environment sky
+
+=================================================================
+*/
+
+#ifdef QUAKE2
+
+
+#define SKY_TEX     2000
+
+/*
+=================================================================
+
+  PCX Loading
+
+=================================================================
+*/
+
+typedef struct
+{
+    char    manufacturer;
+    char    version;
+    char    encoding;
+    char    bits_per_pixel;
+    unsigned short  xmin,ymin,xmax,ymax;
+    unsigned short  hres,vres;
+    unsigned char   palette[48];
+    char    reserved;
+    char    color_planes;
+    unsigned short  bytes_per_line;
+    unsigned short  palette_type;
+    char    filler[58];
+    unsigned    data;           // unbounded
+} pcx_t;
+
+byte    *pcx_rgb;
+
+/*
+============
+LoadPCX
+============
+*/
+void LoadPCX (FILE *f)
+{
+    pcx_t   *pcx, pcxbuf;
+    byte    palette[768];
+    byte    *pix;
+    int     x, y;
+    int     dataByte, runLength;
+    int     count;
+
+//
+// parse the PCX file
+//
+    fread (&pcxbuf, 1, sizeof(pcxbuf), f);
+
+    pcx = &pcxbuf;
+
+    if (pcx->manufacturer != 0x0a
+        || pcx->version != 5
+        || pcx->encoding != 1
+        || pcx->bits_per_pixel != 8
+        || pcx->xmax >= 320
+        || pcx->ymax >= 256)
+    {
+        Con_Printf ("Bad pcx file\n");
+        return;
+    }
+
+    // seek to palette
+    fseek (f, -768, SEEK_END);
+    fread (palette, 1, 768, f);
+
+    fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
+
+    count = (pcx->xmax+1) * (pcx->ymax+1);
+    pcx_rgb = malloc( count * 4);
+
+    for (y=0 ; y<=pcx->ymax ; y++)
+    {
+        pix = pcx_rgb + 4*y*(pcx->xmax+1);
+        for (x=0 ; x<=pcx->ymax ; )
+        {
+            dataByte = fgetc(f);
+
+            if((dataByte & 0xC0) == 0xC0)
+            {
+                runLength = dataByte & 0x3F;
+                dataByte = fgetc(f);
+            }
+            else
+                runLength = 1;
+
+            while(runLength-- > 0)
+            {
+                pix[0] = palette[dataByte*3];
+                pix[1] = palette[dataByte*3+1];
+                pix[2] = palette[dataByte*3+2];
+                pix[3] = 255;
+                pix += 4;
+                x++;
+            }
+        }
+    }
+}
+
+/*
+=========================================================
+
+TARGA LOADING
+
+=========================================================
+*/
+
+typedef struct _TargaHeader {
+    unsigned char   id_length, colormap_type, image_type;
+    unsigned short  colormap_index, colormap_length;
+    unsigned char   colormap_size;
+    unsigned short  x_origin, y_origin, width, height;
+    unsigned char   pixel_size, attributes;
+} TargaHeader;
+
+
+TargaHeader     targa_header;
+byte            *targa_rgba;
+
+int fgetLittleShort (FILE *f)
+{
+    byte    b1, b2;
+
+    b1 = fgetc(f);
+    b2 = fgetc(f);
+
+    return (short)(b1 + b2*256);
+}
+
+int fgetLittleLong (FILE *f)
+{
+    byte    b1, b2, b3, b4;
+
+    b1 = fgetc(f);
+    b2 = fgetc(f);
+    b3 = fgetc(f);
+    b4 = fgetc(f);
+
+    return b1 + (b2<<8) + (b3<<16) + (b4<<24);
+}
+
+
+/*
+=============
+LoadTGA
+=============
+*/
+void LoadTGA (FILE *fin)
+{
+    int             columns, rows, numPixels;
+    byte            *pixbuf;
+    int             row, column;
+
+    targa_header.id_length = fgetc(fin);
+    targa_header.colormap_type = fgetc(fin);
+    targa_header.image_type = fgetc(fin);
+    
+    targa_header.colormap_index = fgetLittleShort(fin);
+    targa_header.colormap_length = fgetLittleShort(fin);
+    targa_header.colormap_size = fgetc(fin);
+    targa_header.x_origin = fgetLittleShort(fin);
+    targa_header.y_origin = fgetLittleShort(fin);
+    targa_header.width = fgetLittleShort(fin);
+    targa_header.height = fgetLittleShort(fin);
+    targa_header.pixel_size = fgetc(fin);
+    targa_header.attributes = fgetc(fin);
+
+    if (targa_header.image_type!=2 
+        && targa_header.image_type!=10) 
+        Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
+
+    if (targa_header.colormap_type !=0 
+        || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
+        Sys_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+
+    columns = targa_header.width;
+    rows = targa_header.height;
+    numPixels = columns * rows;
+
+    targa_rgba = malloc (numPixels*4);
+    
+    if (targa_header.id_length != 0)
+        fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment
+    
+    if (targa_header.image_type==2) {  // Uncompressed, RGB images
+        for(row=rows-1; row>=0; row--) {
+            pixbuf = targa_rgba + row*columns*4;
+            for(column=0; column<columns; column++) {
+                unsigned char red,green,blue,alphabyte;
+                switch (targa_header.pixel_size) {
+                    case 24:
+                            
+                            blue = getc(fin);
+                            green = getc(fin);
+                            red = getc(fin);
+                            *pixbuf++ = red;
+                            *pixbuf++ = green;
+                            *pixbuf++ = blue;
+                            *pixbuf++ = 255;
+                            break;
+                    case 32:
+                            blue = getc(fin);
+                            green = getc(fin);
+                            red = getc(fin);
+                            alphabyte = getc(fin);
+                            *pixbuf++ = red;
+                            *pixbuf++ = green;
+                            *pixbuf++ = blue;
+                            *pixbuf++ = alphabyte;
+                            break;
+                }
+            }
+        }
+    }
+    else if (targa_header.image_type==10) {   // Runlength encoded RGB images
+        unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
+        for(row=rows-1; row>=0; row--) {
+            pixbuf = targa_rgba + row*columns*4;
+            for(column=0; column<columns; ) {
+                packetHeader=getc(fin);
+                packetSize = 1 + (packetHeader & 0x7f);
+                if (packetHeader & 0x80) {        // run-length packet
+                    switch (targa_header.pixel_size) {
+                        case 24:
+                                blue = getc(fin);
+                                green = getc(fin);
+                                red = getc(fin);
+                                alphabyte = 255;
+                                break;
+                        case 32:
+                                blue = getc(fin);
+                                green = getc(fin);
+                                red = getc(fin);
+                                alphabyte = getc(fin);
+                                break;
+                    }
+    
+                    for(j=0;j<packetSize;j++) {
+                        *pixbuf++=red;
+                        *pixbuf++=green;
+                        *pixbuf++=blue;
+                        *pixbuf++=alphabyte;
+                        column++;
+                        if (column==columns) { // run spans across rows
+                            column=0;
+                            if (row>0)
+                                row--;
+                            else
+                                goto breakOut;
+                            pixbuf = targa_rgba + row*columns*4;
+                        }
+                    }
+                }
+                else {                            // non run-length packet
+                    for(j=0;j<packetSize;j++) {
+                        switch (targa_header.pixel_size) {
+                            case 24:
+                                    blue = getc(fin);
+                                    green = getc(fin);
+                                    red = getc(fin);
+                                    *pixbuf++ = red;
+                                    *pixbuf++ = green;
+                                    *pixbuf++ = blue;
+                                    *pixbuf++ = 255;
+                                    break;
+                            case 32:
+                                    blue = getc(fin);
+                                    green = getc(fin);
+                                    red = getc(fin);
+                                    alphabyte = getc(fin);
+                                    *pixbuf++ = red;
+                                    *pixbuf++ = green;
+                                    *pixbuf++ = blue;
+                                    *pixbuf++ = alphabyte;
+                                    break;
+                        }
+                        column++;
+                        if (column==columns) { // pixel packet run spans across rows
+                            column=0;
+                            if (row>0)
+                                row--;
+                            else
+                                goto breakOut;
+                            pixbuf = targa_rgba + row*columns*4;
+                        }                       
+                    }
+                }
+            }
+            breakOut:;
+        }
+    }
+    
+    fclose(fin);
+}
+
+/*
+==================
+R_LoadSkys
+==================
+*/
+char    *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+void R_LoadSkys (void)
+{
+    int     i;
+    FILE    *f;
+    char    name[64];
+
+    for (i=0 ; i<6 ; i++)
+    {
+        GL_Bind (SKY_TEX + i);
+        sprintf (name, "gfx/env/bkgtst%s.tga", suf[i]);
+        COM_FOpenFile (name, &f);
+        if (!f)
+        {
+            Con_Printf ("Couldn't load %s\n", name);
+            continue;
+        }
+        LoadTGA (f);
+//      LoadPCX (f);
+
+        glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, targa_rgba);
+//      glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pcx_rgb);
+
+        free (targa_rgba);
+//      free (pcx_rgb);
+
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    }
+}
+
+
+vec3_t  skyclip[6] = {
+    {1,1,0},
+    {1,-1,0},
+    {0,-1,1},
+    {0,1,1},
+    {1,0,1},
+    {-1,0,1} 
+};
+int c_sky;
+
+// 1 = s, 2 = t, 3 = 2048
+int st_to_vec[6][3] =
+{
+    {3,-1,2},
+    {-3,1,2},
+
+    {1,3,2},
+    {-1,-3,2},
+
+    {-2,-1,3},      // 0 degrees yaw, look straight up
+    {2,-1,-3}       // look straight down
+
+//  {-1,2,3},
+//  {1,2,-3}
+};
+
+// s = [0]/[2], t = [1]/[2]
+int vec_to_st[6][3] =
+{
+    {-2,3,1},
+    {2,3,-1},
+
+    {1,3,2},
+    {-1,3,-2},
+
+    {-2,-1,3},
+    {-2,1,-3}
+
+//  {-1,2,3},
+//  {1,2,-3}
+};
+
+float   skymins[2][6], skymaxs[2][6];
+
+void DrawSkyPolygon (int nump, vec3_t vecs)
+{
+    int     i,j;
+    vec3_t  v, av;
+    float   s, t, dv;
+    int     axis;
+    float   *vp;
+
+    c_sky++;
+#if 0
+glBegin (GL_POLYGON);
+for (i=0 ; i<nump ; i++, vecs+=3)
+{
+    VectorAdd(vecs, r_origin, v);
+    glVertex3fv (v);
+}
+glEnd();
+return;
+#endif
+    // decide which face it maps to
+    VectorCopy (vec3_origin, v);
+    for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
+    {
+        VectorAdd (vp, v, v);
+    }
+    av[0] = fabs(v[0]);
+    av[1] = fabs(v[1]);
+    av[2] = fabs(v[2]);
+    if (av[0] > av[1] && av[0] > av[2])
+    {
+        if (v[0] < 0)
+            axis = 1;
+        else
+            axis = 0;
+    }
+    else if (av[1] > av[2] && av[1] > av[0])
+    {
+        if (v[1] < 0)
+            axis = 3;
+        else
+            axis = 2;
+    }
+    else
+    {
+        if (v[2] < 0)
+            axis = 5;
+        else
+            axis = 4;
+    }
+
+    // project new texture coords
+    for (i=0 ; i<nump ; i++, vecs+=3)
+    {
+        j = vec_to_st[axis][2];
+        if (j > 0)
+            dv = vecs[j - 1];
+        else
+            dv = -vecs[-j - 1];
+
+        j = vec_to_st[axis][0];
+        if (j < 0)
+            s = -vecs[-j -1] / dv;
+        else
+            s = vecs[j-1] / dv;
+        j = vec_to_st[axis][1];
+        if (j < 0)
+            t = -vecs[-j -1] / dv;
+        else
+            t = vecs[j-1] / dv;
+
+        if (s < skymins[0][axis])
+            skymins[0][axis] = s;
+        if (t < skymins[1][axis])
+            skymins[1][axis] = t;
+        if (s > skymaxs[0][axis])
+            skymaxs[0][axis] = s;
+        if (t > skymaxs[1][axis])
+            skymaxs[1][axis] = t;
+    }
+}
+
+#define MAX_CLIP_VERTS  64
+void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
+{
+    float   *norm;
+    float   *v;
+    qboolean    front, back;
+    float   d, e;
+    float   dists[MAX_CLIP_VERTS];
+    int     sides[MAX_CLIP_VERTS];
+    vec3_t  newv[2][MAX_CLIP_VERTS];
+    int     newc[2];
+    int     i, j;
+
+    if (nump > MAX_CLIP_VERTS-2)
+        Sys_Error ("ClipSkyPolygon: MAX_CLIP_VERTS");
+    if (stage == 6)
+    {   // fully clipped, so draw it
+        DrawSkyPolygon (nump, vecs);
+        return;
+    }
+
+    front = back = false;
+    norm = skyclip[stage];
+    for (i=0, v = vecs ; i<nump ; i++, v+=3)
+    {
+        d = DotProduct (v, norm);
+        if (d > ON_EPSILON)
+        {
+            front = true;
+            sides[i] = SIDE_FRONT;
+        }
+        else if (d < ON_EPSILON)
+        {
+            back = true;
+            sides[i] = SIDE_BACK;
+        }
+        else
+            sides[i] = SIDE_ON;
+        dists[i] = d;
+    }
+
+    if (!front || !back)
+    {   // not clipped
+        ClipSkyPolygon (nump, vecs, stage+1);
+        return;
+    }
+
+    // clip it
+    sides[i] = sides[0];
+    dists[i] = dists[0];
+    VectorCopy (vecs, (vecs+(i*3)) );
+    newc[0] = newc[1] = 0;
+
+    for (i=0, v = vecs ; i<nump ; i++, v+=3)
+    {
+        switch (sides[i])
+        {
+        case SIDE_FRONT:
+            VectorCopy (v, newv[0][newc[0]]);
+            newc[0]++;
+            break;
+        case SIDE_BACK:
+            VectorCopy (v, newv[1][newc[1]]);
+            newc[1]++;
+            break;
+        case SIDE_ON:
+            VectorCopy (v, newv[0][newc[0]]);
+            newc[0]++;
+            VectorCopy (v, newv[1][newc[1]]);
+            newc[1]++;
+            break;
+        }
+
+        if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+            continue;
+
+        d = dists[i] / (dists[i] - dists[i+1]);
+        for (j=0 ; j<3 ; j++)
+        {
+            e = v[j] + d*(v[j+3] - v[j]);
+            newv[0][newc[0]][j] = e;
+            newv[1][newc[1]][j] = e;
+        }
+        newc[0]++;
+        newc[1]++;
+    }
+
+    // continue
+    ClipSkyPolygon (newc[0], newv[0][0], stage+1);
+    ClipSkyPolygon (newc[1], newv[1][0], stage+1);
+}
+
+/*
+=================
+R_DrawSkyChain
+=================
+*/
+void R_DrawSkyChain (msurface_t *s)
+{
+    msurface_t  *fa;
+
+    int     i;
+    vec3_t  verts[MAX_CLIP_VERTS];
+    glpoly_t    *p;
+
+    c_sky = 0;
+    GL_Bind(solidskytexture);
+
+    // calculate vertex values for sky box
+
+    for (fa=s ; fa ; fa=fa->texturechain)
+    {
+        for (p=fa->polys ; p ; p=p->next)
+        {
+            for (i=0 ; i<p->numverts ; i++)
+            {
+                VectorSubtract (p->verts[i], r_origin, verts[i]);
+            }
+            ClipSkyPolygon (p->numverts, verts[0], 0);
+        }
+    }
+}
+
+
+/*
+==============
+R_ClearSkyBox
+==============
+*/
+void R_ClearSkyBox (void)
+{
+    int     i;
+
+    for (i=0 ; i<6 ; i++)
+    {
+        skymins[0][i] = skymins[1][i] = 9999;
+        skymaxs[0][i] = skymaxs[1][i] = -9999;
+    }
+}
+
+
+void MakeSkyVec (float s, float t, int axis)
+{
+    vec3_t      v, b;
+    int         j, k;
+
+    b[0] = s*2048;
+    b[1] = t*2048;
+    b[2] = 2048;
+
+    for (j=0 ; j<3 ; j++)
+    {
+        k = st_to_vec[axis][j];
+        if (k < 0)
+            v[j] = -b[-k - 1];
+        else
+            v[j] = b[k - 1];
+        v[j] += r_origin[j];
+    }
+
+    // avoid bilerp seam
+    s = (s+1)*0.5;
+    t = (t+1)*0.5;
+
+    if (s < 1.0/512)
+        s = 1.0/512;
+    else if (s > 511.0/512)
+        s = 511.0/512;
+    if (t < 1.0/512)
+        t = 1.0/512;
+    else if (t > 511.0/512)
+        t = 511.0/512;
+
+    t = 1.0 - t;
+    glTexCoord2f (s, t);
+    glVertex3fv (v);
+}
+
+/*
+==============
+R_DrawSkyBox
+==============
+*/
+int skytexorder[6] = {0,2,1,3,4,5};
+void R_DrawSkyBox (void)
+{
+    int     i, j, k;
+    vec3_t  v;
+    float   s, t;
+
+#if 0
+glEnable (GL_BLEND);
+glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+glColor4f (1,1,1,0.5);
+glDisable (GL_DEPTH_TEST);
+#endif
+    for (i=0 ; i<6 ; i++)
+    {
+        if (skymins[0][i] >= skymaxs[0][i]
+        || skymins[1][i] >= skymaxs[1][i])
+            continue;
+
+        GL_Bind (SKY_TEX+skytexorder[i]);
+#if 0
+skymins[0][i] = -1;
+skymins[1][i] = -1;
+skymaxs[0][i] = 1;
+skymaxs[1][i] = 1;
+#endif
+        glBegin (GL_QUADS);
+        MakeSkyVec (skymins[0][i], skymins[1][i], i);
+        MakeSkyVec (skymins[0][i], skymaxs[1][i], i);
+        MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i);
+        MakeSkyVec (skymaxs[0][i], skymins[1][i], i);
+        glEnd ();
+    }
+#if 0
+glDisable (GL_BLEND);
+glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+glColor4f (1,1,1,0.5);
+glEnable (GL_DEPTH_TEST);
+#endif
+}
+
+
+#endif
+
+//===============================================================
+
+static texture_t* current_sky_mt;
+
+/*
+=============
+R_InitSky
+
+A sky texture is 256*128, with the right side being a masked overlay
+==============
+*/
+void R_InitSky (texture_t *mt)
+{
+    int         i, j, p;
+    byte        *src;
+    unsigned    trans[128*128];
+    unsigned    transpix;
+    int         r, g, b;
+    unsigned    *rgba;
+    // extern   int         skytexturenum;
+    
+    current_sky_mt = mt;
+
+    src = (byte *)mt + mt->offsets[0];
+
+    // make an average value for the back to avoid
+    // a fringe on the top level
+
+    r = g = b = 0;
+    for (i=0 ; i<128 ; i++)
+        for (j=0 ; j<128 ; j++)
+        {
+            p = src[i*256 + j + 128];
+            rgba = &d_8to24table[p];
+            trans[(i*128) + j] = *rgba;
+            r += ((byte *)rgba)[0];
+            g += ((byte *)rgba)[1];
+            b += ((byte *)rgba)[2];
+        }
+
+    ((byte *)&transpix)[0] = r/(128*128);
+    ((byte *)&transpix)[1] = g/(128*128);
+    ((byte *)&transpix)[2] = b/(128*128);
+    ((byte *)&transpix)[3] = 0;
+
+
+    if (!solidskytexture)
+        solidskytexture = texture_extension_number++;
+    GL_Bind (solidskytexture );
+    glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_solid_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+
+    for (i=0 ; i<128 ; i++)
+        for (j=0 ; j<128 ; j++)
+        {
+            p = src[i*256 + j];
+            if (p == 0)
+                trans[(i*128) + j] = transpix;
+            else
+                trans[(i*128) + j] = d_8to24table[p];
+        }
+
+    if (!alphaskytexture)
+        alphaskytexture = texture_extension_number++;
+    GL_Bind(alphaskytexture);
+    glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+}
+
+void R_ReloadSky() {
+    if (current_sky_mt) {
+        R_InitSky(current_sky_mt);
+    }
+}
diff --git a/quake/src/WinQuake/glquake.h b/quake/src/WinQuake/glquake.h
index 45bdfff..0c0379f 100644
--- a/quake/src/WinQuake/glquake.h
+++ b/quake/src/WinQuake/glquake.h
@@ -1,40 +1,52 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // disable data conversion warnings
 
+#ifdef _WIN32
 #pragma warning(disable : 4244)     // MIPS
 #pragma warning(disable : 4136)     // X86
 #pragma warning(disable : 4051)     // ALPHA
+#endif
   
 #ifdef _WIN32
 #include <windows.h>
 #endif
 
+#ifdef USE_OPENGLES
+
+#include <GLES/gl.h>
+
+#else
+
 #include <GL/gl.h>
 #include <GL/glu.h>
 
+#endif
+
 void GL_BeginRendering (int *x, int *y, int *width, int *height);
 void GL_EndRendering (void);
 
+#ifdef USE_OPENGLES
 
-#ifdef _WIN32
+#else // full OpenGL
+
 // Function prototypes for the Texture Object Extension routines
 typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,
                     const GLboolean *);
@@ -49,7 +61,8 @@
 extern	BINDTEXFUNCPTR bindTexFunc;
 extern	DELTEXFUNCPTR delTexFunc;
 extern	TEXSUBIMAGEPTR TexSubImage2DFunc;
-#endif
+
+#endif // USE_OPENGLES
 
 extern	int texture_extension_number;
 extern	int		texture_mode;
@@ -58,8 +71,8 @@
 
 void GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap, qboolean alpha);
 void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
-int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha);
-int GL_FindTexture (char *identifier);
+int GL_LoadTexture (const char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha);
+int GL_FindTexture (const char *identifier);
 
 typedef struct
 {
@@ -129,7 +142,8 @@
 
 
 typedef enum {
-	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2
+	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2,
+	ptype_t_max = 1 << 30
 } ptype_t;
 
 // !!! if this is changed, it must be changed in d_ifacea.h too !!!
@@ -233,18 +247,26 @@
 void GL_Bind (int texnum);
 
 // Multitexture
+#ifdef USE_OPENGLES
+
+#define    TEXTURE0_SGIS				GL_TEXTURE0
+#define    TEXTURE1_SGIS				GL_TEXTURE1
+
+#else
 #define    TEXTURE0_SGIS				0x835E
 #define    TEXTURE1_SGIS				0x835F
+#endif
 
 #ifndef _WIN32
 #define APIENTRY /* */
-#endif
 
 typedef void (APIENTRY *lpMTexFUNC) (GLenum, GLfloat, GLfloat);
 typedef void (APIENTRY *lpSelTexFUNC) (GLenum);
 extern lpMTexFUNC qglMTexCoord2fSGIS;
 extern lpSelTexFUNC qglSelectTextureSGIS;
 
+#endif
+
 extern qboolean gl_mtexable;
 
 void GL_DisableMultitexture(void);
diff --git a/quake/src/WinQuake/glquake2.h b/quake/src/WinQuake/glquake2.h
deleted file mode 100644
index 877f546..0000000
--- a/quake/src/WinQuake/glquake2.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// disable data conversion warnings

-

-#pragma warning(disable : 4244)     // MIPS

-#pragma warning(disable : 4136)     // X86

-#pragma warning(disable : 4051)     // ALPHA

-  

-#include <windows.h>

-

-#include <gl\gl.h>

-#include <gl\glu.h>

-

-void GL_BeginRendering (int *x, int *y, int *width, int *height);

-void GL_EndRendering (void);

-

-

-// Function prototypes for the Texture Object Extension routines

-typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,

-                    const GLboolean *);

-typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint);

-typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *);

-typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *);

-typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint);

-typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *,

-                    const GLclampf *);

-typedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *);

-

-extern	BINDTEXFUNCPTR bindTexFunc;

-extern	DELTEXFUNCPTR delTexFunc;

-extern	TEXSUBIMAGEPTR TexSubImage2DFunc;

-

-extern	int texture_extension_number;

-extern	int		texture_mode;

-

-extern	float	gldepthmin, gldepthmax;

-

-void GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap, qboolean alpha, qboolean modulate);

-void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha, qboolean modulate);

-int GL_LoadTexture (char *identifier, int width, int height, byte *data, int mipmap, int alpha, int modulate);

-int GL_FindTexture (char *identifier);

-

-typedef struct

-{

-	float	x, y, z;

-	float	s, t;

-	float	r, g, b;

-} glvert_t;

-

-extern glvert_t glv;

-

-extern	int glx, gly, glwidth, glheight;

-

-extern	PROC glArrayElementEXT;

-extern	PROC glColorPointerEXT;

-extern	PROC glTexturePointerEXT;

-extern	PROC glVertexPointerEXT;

-

-

-// r_local.h -- private refresh defs

-

-#define MAXALIASVERTS		2000	// TODO: tune this

-

-#define ALIAS_BASE_SIZE_RATIO		(1.0 / 11.0)

-					// normalizing factor so player model works out to about

-					//  1 pixel per triangle

-#define	MAX_LBM_HEIGHT		480

-

-#define TILE_SIZE		128		// size of textures generated by R_GenTiledSurf

-

-#define SKYSHIFT		7

-#define	SKYSIZE			(1 << SKYSHIFT)

-#define SKYMASK			(SKYSIZE - 1)

-

-#define BACKFACE_EPSILON	0.01

-

-

-void R_TimeRefresh_f (void);

-void R_ReadPointFile_f (void);

-texture_t *R_TextureAnimation (texture_t *base);

-

-typedef struct surfcache_s

-{

-	struct surfcache_s	*next;

-	struct surfcache_s 	**owner;		// NULL is an empty chunk of memory

-	int					lightadj[MAXLIGHTMAPS]; // checked for strobe flush

-	int					dlight;

-	int					size;		// including header

-	unsigned			width;

-	unsigned			height;		// DEBUG only needed for debug

-	float				mipscale;

-	struct texture_s	*texture;	// checked for animating textures

-	byte				data[4];	// width*height elements

-} surfcache_t;

-

-

-typedef struct

-{

-	pixel_t		*surfdat;	// destination for generated surface

-	int			rowbytes;	// destination logical width in bytes

-	msurface_t	*surf;		// description for surface to generate

-	fixed8_t	lightadj[MAXLIGHTMAPS];

-							// adjust for lightmap levels for dynamic lighting

-	texture_t	*texture;	// corrected for animating textures

-	int			surfmip;	// mipmapped ratio of surface texels / world pixels

-	int			surfwidth;	// in mipmapped texels

-	int			surfheight;	// in mipmapped texels

-} drawsurf_t;

-

-

-typedef enum {

-	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2

-} ptype_t;

-

-// !!! if this is changed, it must be changed in d_ifacea.h too !!!

-typedef struct particle_s

-{

-// driver-usable fields

-	vec3_t		org;

-	float		color;

-// drivers never touch the following fields

-	struct particle_s	*next;

-	vec3_t		vel;

-	float		ramp;

-	float		die;

-	ptype_t		type;

-} particle_t;

-

-

-//====================================================

-

-

-extern	entity_t	r_worldentity;

-extern	qboolean	r_cache_thrash;		// compatability

-extern	vec3_t		modelorg, r_entorigin;

-extern	entity_t	*currententity;

-extern	int			r_visframecount;	// ??? what difs?

-extern	int			r_framecount;

-extern	mplane_t	frustum[4];

-extern	int		c_brush_polys, c_alias_polys;

-

-

-//

-// view origin

-//

-extern	vec3_t	vup;

-extern	vec3_t	vpn;

-extern	vec3_t	vright;

-extern	vec3_t	r_origin;

-

-//

-// screen size info

-//

-extern	refdef_t	r_refdef;

-extern	mleaf_t		*r_viewleaf, *r_oldviewleaf;

-extern	texture_t	*r_notexture_mip;

-extern	int		d_lightstylevalue[256];	// 8.8 fraction of base light value

-

-extern	qboolean	envmap;

-extern	int	currenttexture;

-extern	int	particletexture;

-extern	int	playertextures;

-

-extern	int	skytexturenum;		// index in cl.loadmodel, not gl texture object

-

-extern	cvar_t	r_drawentities;

-extern	cvar_t	r_drawworld;

-extern	cvar_t	r_drawviewmodel;

-extern	cvar_t	r_speeds;

-extern	cvar_t	r_waterwarp;

-extern	cvar_t	r_fullbright;

-extern	cvar_t	r_lightmap;

-extern	cvar_t	r_shadows;

-extern	cvar_t	r_dynamic;

-

-extern	cvar_t	gl_clear;

-extern	cvar_t	gl_cull;

-extern	cvar_t	gl_poly;

-extern	cvar_t	gl_texsort;

-extern	cvar_t	gl_smoothmodels;

-extern	cvar_t	gl_affinemodels;

-extern	cvar_t	gl_fogblend;

-extern	cvar_t	gl_polyblend;

-extern	cvar_t	gl_keeptjunctions;

-extern	cvar_t	gl_reporttjunctions;

-

-extern	int		gl_lightmap_format;

-extern	int		gl_solid_format;

-extern	int		gl_alpha_format;

-

-void R_TranslatePlayerSkin (int playernum);

-void GL_Bind (int texnum);

diff --git a/quake/src/WinQuake/host.c b/quake/src/WinQuake/host.cpp
old mode 100644
new mode 100755
similarity index 91%
rename from quake/src/WinQuake/host.c
rename to quake/src/WinQuake/host.cpp
index 9772d6d..670d7a0
--- a/quake/src/WinQuake/host.c
+++ b/quake/src/WinQuake/host.cpp
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // host.c -- coordinates spawning and killing of local servers
 
 #include "quakedef.h"
@@ -54,32 +54,32 @@
 byte		*host_basepal;
 byte		*host_colormap;
 
-cvar_t	host_framerate = {"host_framerate","0"};	// set for slow motion
-cvar_t	host_speeds = {"host_speeds","0"};			// set for running times
+cvar_t	host_framerate = CVAR2("host_framerate","0");	// set for slow motion
+cvar_t	host_speeds = CVAR2("host_speeds","0");			// set for running times
 
-cvar_t	sys_ticrate = {"sys_ticrate","0.05"};
-cvar_t	serverprofile = {"serverprofile","0"};
+cvar_t	sys_ticrate = CVAR2("sys_ticrate","0.05");
+cvar_t	serverprofile = CVAR2("serverprofile","0");
 
-cvar_t	fraglimit = {"fraglimit","0",false,true};
-cvar_t	timelimit = {"timelimit","0",false,true};
-cvar_t	teamplay = {"teamplay","0",false,true};
+cvar_t	fraglimit = CVAR4("fraglimit","0",false,true);
+cvar_t	timelimit = CVAR4("timelimit","0",false,true);
+cvar_t	teamplay = CVAR4("teamplay","0",false,true);
 
-cvar_t	samelevel = {"samelevel","0"};
-cvar_t	noexit = {"noexit","0",false,true};
+cvar_t	samelevel = CVAR2("samelevel","0");
+cvar_t	noexit = CVAR4("noexit","0",false,true);
 
 #ifdef QUAKE2
-cvar_t	developer = {"developer","1"};	// should be 0 for release!
+cvar_t	developer = CVAR2("developer","1");	// should be 0 for release!
 #else
-cvar_t	developer = {"developer","0"};
+cvar_t	developer = CVAR2("developer","0");
 #endif
 
-cvar_t	skill = {"skill","1"};						// 0 - 3
-cvar_t	deathmatch = {"deathmatch","0"};			// 0, 1, or 2
-cvar_t	coop = {"coop","0"};			// 0 or 1
+cvar_t	skill = CVAR2("skill","1");						// 0 - 3
+cvar_t	deathmatch = CVAR2("deathmatch","0");			// 0, 1, or 2
+cvar_t	coop = CVAR2("coop","0");			// 0 or 1
 
-cvar_t	pausable = {"pausable","1"};
+cvar_t	pausable = CVAR2("pausable","1");
 
-cvar_t	temp1 = {"temp1","0"};
+cvar_t	temp1 = CVAR2("temp1","0");
 
 
 /*
@@ -87,7 +87,7 @@
 Host_EndGame
 ================
 */
-void Host_EndGame (char *message, ...)
+void Host_EndGame (const char *message, ...)
 {
 	va_list		argptr;
 	char		string[1024];
@@ -118,7 +118,7 @@
 This shuts down both the client and server
 ================
 */
-void Host_Error (char *error, ...)
+void Host_Error (const char *error, ...)
 {
 	va_list		argptr;
 	char		string[1024];
@@ -192,7 +192,7 @@
 	svs.maxclientslimit = svs.maxclients;
 	if (svs.maxclientslimit < 4)
 		svs.maxclientslimit = 4;
-	svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
+	svs.clients = (client_s*) Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
 
 	if (svs.maxclients > 1)
 		Cvar_SetValue ("deathmatch", 1.0);
@@ -274,7 +274,7 @@
 FIXME: make this just a stuffed echo?
 =================
 */
-void SV_ClientPrintf (char *fmt, ...)
+void SV_ClientPrintf (const char *fmt, ...)
 {
 	va_list		argptr;
 	char		string[1024];
@@ -294,7 +294,7 @@
 Sends text to all active clients
 =================
 */
-void SV_BroadcastPrintf (char *fmt, ...)
+void SV_BroadcastPrintf (const char *fmt, ...)
 {
 	va_list		argptr;
 	char		string[1024];
@@ -319,7 +319,7 @@
 Send text over to the client to be executed
 =================
 */
-void Host_ClientCommands (char *fmt, ...)
+void Host_ClientCommands (const char *fmt, ...)
 {
 	va_list		argptr;
 	char		string[1024];
@@ -446,7 +446,7 @@
 	while (count);
 
 // make sure all the clients know we're disconnecting
-	buf.data = message;
+	buf.data = (byte*) message;
 	buf.maxsize = 4;
 	buf.cursize = 0;
 	MSG_WriteByte(&buf, svc_disconnect);
@@ -715,10 +715,10 @@
 
 	if (host_speeds.value)
 	{
-		pass1 = (time1 - time3)*1000;
+		pass1 = (int) ((time1 - time3)*1000);
 		time3 = Sys_FloatTime ();
-		pass2 = (time2 - time1)*1000;
-		pass3 = (time3 - time2)*1000;
+		pass2 = (int) ((time2 - time1)*1000);
+		pass3 = (int) ((time3 - time2)*1000);
 		Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
 					pass1+pass2+pass3, pass1, pass2, pass3);
 	}
@@ -749,7 +749,7 @@
 	if (timecount < 1000)
 		return;
 
-	m = timetotal*1000/timecount;
+	m = (int) (timetotal*1000/timecount);
 	timecount = 0;
 	timetotal = 0;
 	c = 0;
@@ -788,12 +788,12 @@
 			Sys_Error("Invalid signature in vcr file\n");
 
 		Sys_FileRead (vcrFile, &com_argc, sizeof(int));
-		com_argv = malloc(com_argc * sizeof(char *));
+		com_argv = (const char**) malloc(com_argc * sizeof(char *));
 		com_argv[0] = parms->argv[0];
 		for (i = 0; i < com_argc; i++)
 		{
 			Sys_FileRead (vcrFile, &len, sizeof(int));
-			p = malloc(len);
+			p = (char*) malloc(len);
 			Sys_FileRead (vcrFile, p, len);
 			com_argv[i+1] = p;
 		}
@@ -890,10 +890,13 @@
 		Draw_Init ();
 		SCR_Init ();
 		R_Init ();
-#ifndef	_WIN32
+
+#ifndef _WIN32
 	// on Win32, sound initialization has to come before video initialization, so we
 	// can put up a popup if the sound hardware is in use
-		S_Init ();
+
+	// Actually S_Init is called from inside VID_Init. So don't call here.
+	// 	S_Init ();
 #else
 
 #ifdef	GLQUAKE
diff --git a/quake/src/WinQuake/host_cmd.c b/quake/src/WinQuake/host_cmd.cpp
old mode 100644
new mode 100755
similarity index 87%
rename from quake/src/WinQuake/host_cmd.c
rename to quake/src/WinQuake/host_cmd.cpp
index 073feaa..b5964f9
--- a/quake/src/WinQuake/host_cmd.c
+++ b/quake/src/WinQuake/host_cmd.cpp
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 
 #include "quakedef.h"
 
@@ -34,6 +34,8 @@
 
 extern void M_Menu_Quit_f (void);
 
+void Host_Quit();
+
 void Host_Quit_f (void)
 {
 	if (key_dest != key_console && cls.state != ca_dedicated)
@@ -41,8 +43,13 @@
 		M_Menu_Quit_f ();
 		return;
 	}
+	Host_Quit();
+}
+
+void Host_Quit()
+{
 	CL_Disconnect ();
-	Host_ShutdownServer(false);		
+	Host_ShutdownServer(false);
 
 	Sys_Quit ();
 }
@@ -60,8 +67,8 @@
 	int			minutes;
 	int			hours = 0;
 	int			j;
-	void		(*print) (char *fmt, ...);
-	
+	void		(*print) (const char *fmt, ...);
+
 	if (cmd_source == src_command)
 	{
 		if (!sv.active)
@@ -97,7 +104,7 @@
 		}
 		else
 			hours = 0;
-		print ("#%-2u %-16.16s  %3i  %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds);
+		print ("#%-2u %-16.16s  %3i  %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->u.v.frags, hours, minutes, seconds);
 		print ("   %s\n", client->netconnection->address);
 	}
 }
@@ -121,8 +128,8 @@
 	if (pr_global_struct->deathmatch && !host_client->privileged)
 		return;
 
-	sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;
-	if (!((int)sv_player->v.flags & FL_GODMODE) )
+	sv_player->u.v.flags = (int)sv_player->u.v.flags ^ FL_GODMODE;
+	if (!((int)sv_player->u.v.flags & FL_GODMODE) )
 		SV_ClientPrintf ("godmode OFF\n");
 	else
 		SV_ClientPrintf ("godmode ON\n");
@@ -139,8 +146,8 @@
 	if (pr_global_struct->deathmatch && !host_client->privileged)
 		return;
 
-	sv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET;
-	if (!((int)sv_player->v.flags & FL_NOTARGET) )
+	sv_player->u.v.flags = (int)sv_player->u.v.flags ^ FL_NOTARGET;
+	if (!((int)sv_player->u.v.flags & FL_NOTARGET) )
 		SV_ClientPrintf ("notarget OFF\n");
 	else
 		SV_ClientPrintf ("notarget ON\n");
@@ -159,16 +166,16 @@
 	if (pr_global_struct->deathmatch && !host_client->privileged)
 		return;
 
-	if (sv_player->v.movetype != MOVETYPE_NOCLIP)
+	if (sv_player->u.v.movetype != MOVETYPE_NOCLIP)
 	{
 		noclip_anglehack = true;
-		sv_player->v.movetype = MOVETYPE_NOCLIP;
+		sv_player->u.v.movetype = MOVETYPE_NOCLIP;
 		SV_ClientPrintf ("noclip ON\n");
 	}
 	else
 	{
 		noclip_anglehack = false;
-		sv_player->v.movetype = MOVETYPE_WALK;
+		sv_player->u.v.movetype = MOVETYPE_WALK;
 		SV_ClientPrintf ("noclip OFF\n");
 	}
 }
@@ -191,14 +198,14 @@
 	if (pr_global_struct->deathmatch && !host_client->privileged)
 		return;
 
-	if (sv_player->v.movetype != MOVETYPE_FLY)
+	if (sv_player->u.v.movetype != MOVETYPE_FLY)
 	{
-		sv_player->v.movetype = MOVETYPE_FLY;
+		sv_player->u.v.movetype = MOVETYPE_FLY;
 		SV_ClientPrintf ("flymode ON\n");
 	}
 	else
 	{
-		sv_player->v.movetype = MOVETYPE_WALK;
+		sv_player->u.v.movetype = MOVETYPE_WALK;
 		SV_ClientPrintf ("flymode OFF\n");
 	}
 }
@@ -215,7 +222,7 @@
 	int		i, j;
 	float	total;
 	client_t	*client;
-	
+
 	if (cmd_source == src_command)
 	{
 		Cmd_ForwardToServer ();
@@ -248,7 +255,7 @@
 ======================
 Host_Map_f
 
-handle a 
+handle a
 map <servername>
 command from the console.  Active clients are kicked off.
 ======================
@@ -264,7 +271,7 @@
 	cls.demonum = -1;		// stop demo loop in case this fails
 
 	CL_Disconnect ();
-	Host_ShutdownServer(false);		
+	Host_ShutdownServer(false);
 
 	key_dest = key_game;			// remove console or menu
 	SCR_BeginLoadingPlaque ();
@@ -286,7 +293,7 @@
 #endif
 	if (!sv.active)
 		return;
-	
+
 	if (cls.state != ca_dedicated)
 	{
 		strcpy (cls.spawnparms, "");
@@ -296,9 +303,9 @@
 			strcat (cls.spawnparms, Cmd_Argv(i));
 			strcat (cls.spawnparms, " ");
 		}
-		
-		Cmd_ExecuteString ("connect local", src_command);
-	}	
+
+		Cmd_ExecuteString2 ("connect local", src_command);
+	}
 }
 
 /*
@@ -409,7 +416,7 @@
 void Host_Connect_f (void)
 {
 	char	name[MAX_QPATH];
-	
+
 	cls.demonum = -1;		// stop demo loop in case this fails
 	if (cls.demoplayback)
 	{
@@ -436,7 +443,7 @@
 ===============
 Host_SavegameComment
 
-Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current 
+Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
 ===============
 */
 void Host_SavegameComment (char *text)
@@ -501,10 +508,10 @@
 		Con_Printf ("Relative pathnames are not allowed.\n");
 		return;
 	}
-		
+
 	for (i=0 ; i<svs.maxclients ; i++)
 	{
-		if (svs.clients[i].active && (svs.clients[i].edict->v.health <= 0) )
+		if (svs.clients[i].active && (svs.clients[i].edict->u.v.health <= 0) )
 		{
 			Con_Printf ("Can't savegame with a dead player\n");
 			return;
@@ -513,7 +520,7 @@
 
 	sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
 	COM_DefaultExtension (name, ".sav");
-	
+
 	Con_Printf ("Saving game to %s...\n", name);
 	f = fopen (name, "w");
 	if (!f)
@@ -521,7 +528,7 @@
 		Con_Printf ("ERROR: couldn't open.\n");
 		return;
 	}
-	
+
 	fprintf (f, "%i\n", SAVEGAME_VERSION);
 	Host_SavegameComment (comment);
 	fprintf (f, "%s\n", comment);
@@ -584,7 +591,7 @@
 
 	sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
 	COM_DefaultExtension (name, ".sav");
-	
+
 // we can't call SCR_BeginLoadingPlaque, because too much stack space has
 // been used.  The menu calls it before stuffing loadgame command
 //	SCR_BeginLoadingPlaque ();
@@ -622,7 +629,7 @@
 	fscanf (f, "%f\n",&time);
 
 	CL_Disconnect_f ();
-	
+
 #ifdef QUAKE2
 	SV_SpawnServer (mapname, NULL);
 #else
@@ -641,7 +648,7 @@
 	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
 	{
 		fscanf (f, "%s\n", str);
-		sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
+		sv.lightstyles[i] = (char*) Hunk_Alloc (strlen(str)+1);
 		strcpy (sv.lightstyles[i], str);
 	}
 
@@ -649,7 +656,7 @@
 	entnum = -1;		// -1 is the globals
 	while (!feof(f))
 	{
-		for (i=0 ; i<sizeof(str)-1 ; i++)
+		for (i=0 ; i< (int) (sizeof(str)-1) ; i++)
 		{
 			r = fgetc (f);
 			if (r == EOF || !r)
@@ -670,7 +677,7 @@
 			break;		// end of file
 		if (strcmp(com_token,"{"))
 			Sys_Error ("First token isn't a brace");
-			
+
 		if (entnum == -1)
 		{	// parse the global vars
 			ED_ParseGlobals (start);
@@ -679,10 +686,10 @@
 		{	// parse an edict
 
 			ent = EDICT_NUM(entnum);
-			memset (&ent->v, 0, progs->entityfields * 4);
+			memset (&ent->u.v, 0, progs->entityfields * 4);
 			ent->free = false;
 			ED_ParseEdict (start, ent);
-	
+
 		// link it into the bsp tree
 			if (!ent->free)
 				SV_LinkEdict (ent, false);
@@ -690,7 +697,7 @@
 
 		entnum++;
 	}
-	
+
 	sv.num_edicts = entnum;
 	sv.time = time;
 
@@ -716,7 +723,7 @@
 	edict_t	*ent;
 
 	sprintf (name, "%s/%s.gip", com_gamedir, sv.name);
-	
+
 	Con_Printf ("Saving game to %s...\n", name);
 	f = fopen (name, "w");
 	if (!f)
@@ -724,7 +731,7 @@
 		Con_Printf ("ERROR: couldn't open.\n");
 		return;
 	}
-	
+
 	fprintf (f, "%i\n", SAVEGAME_VERSION);
 	Host_SavegameComment (comment);
 	fprintf (f, "%s\n", comment);
@@ -748,7 +755,7 @@
 	for (i=svs.maxclients+1 ; i<sv.num_edicts ; i++)
 	{
 		ent = EDICT_NUM(i);
-		if ((int)ent->v.flags & FL_ARCHIVE_OVERRIDE)
+		if ((int)ent->u.v.flags & FL_ARCHIVE_OVERRIDE)
 			continue;
 		fprintf (f, "%i\n",i);
 		ED_Write (f, ent);
@@ -772,7 +779,7 @@
 //	float	spawn_parms[NUM_SPAWN_PARMS];
 
 	sprintf (name, "%s/%s.gip", com_gamedir, level);
-	
+
 	Con_Printf ("Loading game from %s...\n", name);
 	f = fopen (name, "r");
 	if (!f)
@@ -838,19 +845,19 @@
 			break;		// end of file
 		if (strcmp(com_token,"{"))
 			Sys_Error ("First token isn't a brace");
-			
+
 		// parse an edict
 
 		ent = EDICT_NUM(entnum);
 		memset (&ent->v, 0, progs->entityfields * 4);
 		ent->free = false;
 		ED_ParseEdict (start, ent);
-	
+
 		// link it into the bsp tree
 		if (!ent->free)
 			SV_LinkEdict (ent, false);
 	}
-	
+
 //	sv.num_edicts = entnum;
 	sv.time = time;
 	fclose (f);
@@ -917,7 +924,7 @@
 		return;
 	}
 	if (Cmd_Argc () == 2)
-		newName = Cmd_Argv(1);	
+		newName = Cmd_Argv(1);
 	else
 		newName = Cmd_Args();
 	newName[15] = 0;
@@ -936,16 +943,16 @@
 		if (Q_strcmp(host_client->name, newName) != 0)
 			Con_Printf ("%s renamed to %s\n", host_client->name, newName);
 	Q_strcpy (host_client->name, newName);
-	host_client->edict->v.netname = host_client->name - pr_strings;
-	
+	host_client->edict->u.v.netname = host_client->name - pr_strings;
+
 // send notification to all clients
-	
+
 	MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
 	MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
 	MSG_WriteString (&sv.reliable_datagram, host_client->name);
 }
 
-	
+
 void Host_Version_f (void)
 {
 	Con_Printf ("Version %4.2f\n", VERSION);
@@ -957,7 +964,7 @@
 {
 	client_t *cl;
 	int			j;
-	
+
 	if (cmd_source != src_command)
 		return;
 
@@ -972,8 +979,8 @@
 		if (cl->privileged)
 		{
 			cl->privileged = false;
-			cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
-			cl->edict->v.movetype = MOVETYPE_WALK;
+			cl->edict->u.v.flags = (int)cl->edict->u.v.flags & ~(FL_GODMODE|FL_NOTARGET);
+			cl->edict->u.v.movetype = MOVETYPE_WALK;
 			noclip_anglehack = false;
 		}
 		else
@@ -992,8 +999,8 @@
 			if (cl->privileged)
 			{
 				cl->privileged = false;
-				cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
-				cl->edict->v.movetype = MOVETYPE_WALK;
+				cl->edict->u.v.flags = (int)cl->edict->u.v.flags & ~(FL_GODMODE|FL_NOTARGET);
+				cl->edict->u.v.movetype = MOVETYPE_WALK;
 				noclip_anglehack = false;
 			}
 			else
@@ -1043,22 +1050,22 @@
 
 // turn on color set 1
 	if (!fromServer)
-		sprintf (text, "%c%s: ", 1, save->name);
+		sprintf ((char*) text, "%c%s: ", 1, save->name);
 	else
-		sprintf (text, "%c<%s> ", 1, hostname.string);
+		sprintf ((char*) text, "%c<%s> ", 1, hostname.string);
 
-	j = sizeof(text) - 2 - Q_strlen(text);  // -2 for /n and null terminator
-	if (Q_strlen(p) > j)
+	j = sizeof(text) - 2 - Q_strlen((char*) text);  // -2 for /n and null terminator
+	if (Q_strlen((char*) p) > j)
 		p[j] = 0;
 
-	strcat (text, p);
-	strcat (text, "\n");
+	strcat ((char*) text, p);
+	strcat ((char*) text, "\n");
 
 	for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
 	{
 		if (!client || !client->active || !client->spawned)
 			continue;
-		if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team)
+		if (teamplay.value && teamonly && client->edict->u.v.team != save->edict->u.v.team)
 			continue;
 		host_client = client;
 		SV_ClientPrintf("%s", text);
@@ -1142,7 +1149,7 @@
 {
 	int		top, bottom;
 	int		playercolor;
-	
+
 	if (Cmd_Argc() == 1)
 	{
 		Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f);
@@ -1157,14 +1164,14 @@
 		top = atoi(Cmd_Argv(1));
 		bottom = atoi(Cmd_Argv(2));
 	}
-	
+
 	top &= 15;
 	if (top > 13)
 		top = 13;
 	bottom &= 15;
 	if (bottom > 13)
 		bottom = 13;
-	
+
 	playercolor = top*16 + bottom;
 
 	if (cmd_source == src_command)
@@ -1176,7 +1183,7 @@
 	}
 
 	host_client->colors = playercolor;
-	host_client->edict->v.team = bottom + 1;
+	host_client->edict->u.v.team = bottom + 1;
 
 // send notification to all clients
 	MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
@@ -1197,12 +1204,12 @@
 		return;
 	}
 
-	if (sv_player->v.health <= 0)
+	if (sv_player->u.v.health <= 0)
 	{
 		SV_ClientPrintf ("Can't suicide -- allready dead!\n");
 		return;
 	}
-	
+
 	pr_global_struct->time = sv.time;
 	pr_global_struct->self = EDICT_TO_PROG(sv_player);
 	PR_ExecuteProgram (pr_global_struct->ClientKill);
@@ -1216,7 +1223,7 @@
 */
 void Host_Pause_f (void)
 {
-	
+
 	if (cmd_source == src_command)
 	{
 		Cmd_ForwardToServer ();
@@ -1230,11 +1237,11 @@
 
 		if (sv.paused)
 		{
-			SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->v.netname);
+			SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->u.v.netname);
 		}
 		else
 		{
-			SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->v.netname);
+			SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->u.v.netname);
 		}
 
 	// send notification to all clients
@@ -1264,7 +1271,7 @@
 		Con_Printf ("prespawn not valid -- allready spawned\n");
 		return;
 	}
-	
+
 	SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);
 	MSG_WriteByte (&host_client->message, svc_signonnum);
 	MSG_WriteByte (&host_client->message, 2);
@@ -1305,10 +1312,10 @@
 		// set up the edict
 		ent = host_client->edict;
 
-		memset (&ent->v, 0, progs->entityfields * 4);
-		ent->v.colormap = NUM_FOR_EDICT(ent);
-		ent->v.team = (host_client->colors & 15) + 1;
-		ent->v.netname = host_client->name - pr_strings;
+		memset (&ent->u.v, 0, progs->entityfields * 4);
+		ent->u.v.colormap = NUM_FOR_EDICT(ent);
+		ent->u.v.team = (host_client->colors & 15) + 1;
+		ent->u.v.netname = host_client->name - pr_strings;
 
 		// copy spawn parms out of the client_t
 
@@ -1324,7 +1331,7 @@
 		if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time)
 			Sys_Printf ("%s entered the game\n", host_client->name);
 
-		PR_ExecuteProgram (pr_global_struct->PutClientInServer);	
+		PR_ExecuteProgram (pr_global_struct->PutClientInServer);
 	}
 
 
@@ -1347,7 +1354,7 @@
 		MSG_WriteByte (&host_client->message, i);
 		MSG_WriteByte (&host_client->message, client->colors);
 	}
-	
+
 // send all current light styles
 	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
 	{
@@ -1361,21 +1368,21 @@
 //
 	MSG_WriteByte (&host_client->message, svc_updatestat);
 	MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
-	MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets);
+	MSG_WriteLong (&host_client->message, (int) pr_global_struct->total_secrets);
 
 	MSG_WriteByte (&host_client->message, svc_updatestat);
 	MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
-	MSG_WriteLong (&host_client->message, pr_global_struct->total_monsters);
+	MSG_WriteLong (&host_client->message, (int) pr_global_struct->total_monsters);
 
 	MSG_WriteByte (&host_client->message, svc_updatestat);
 	MSG_WriteByte (&host_client->message, STAT_SECRETS);
-	MSG_WriteLong (&host_client->message, pr_global_struct->found_secrets);
+	MSG_WriteLong (&host_client->message, (int) pr_global_struct->found_secrets);
 
 	MSG_WriteByte (&host_client->message, svc_updatestat);
 	MSG_WriteByte (&host_client->message, STAT_MONSTERS);
-	MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters);
+	MSG_WriteLong (&host_client->message, (int) pr_global_struct->killed_monsters);
 
-	
+
 //
 // send a fixangle
 // Never send a roll angle, because savegames can catch the server
@@ -1385,7 +1392,7 @@
 	ent = EDICT_NUM( 1 + (host_client - svs.clients) );
 	MSG_WriteByte (&host_client->message, svc_setangle);
 	for (i=0 ; i < 2 ; i++)
-		MSG_WriteAngle (&host_client->message, ent->v.angles[i] );
+		MSG_WriteAngle (&host_client->message, ent->u.v.angles[i] );
 	MSG_WriteAngle (&host_client->message, 0 );
 
 	SV_WriteClientdataToMessage (sv_player, &host_client->message);
@@ -1423,8 +1430,8 @@
 */
 void Host_Kick_f (void)
 {
-	char		*who;
-	char		*message = NULL;
+	const char		*who;
+	const char		*message = NULL;
 	client_t	*save;
 	int			i;
 	qboolean	byNumber = false;
@@ -1444,7 +1451,7 @@
 
 	if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0)
 	{
-		i = Q_atof(Cmd_Argv(2)) - 1;
+		i = (int) Q_atof(Cmd_Argv(2)) - 1;
 		if (i < 0 || i >= svs.maxclients)
 			return;
 		if (!svs.clients[i].active)
@@ -1530,7 +1537,7 @@
 
 	t = Cmd_Argv(1);
 	v = atoi (Cmd_Argv(2));
-	
+
 	switch (t[0])
 	{
    case '0':
@@ -1549,24 +1556,24 @@
          if (t[0] == '6')
          {
             if (t[1] == 'a')
-               sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN;
+               sv_player->u.v.items = (int)sv_player->u.v.items | HIT_PROXIMITY_GUN;
             else
-               sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER;
+               sv_player->u.v.items = (int)sv_player->u.v.items | IT_GRENADE_LAUNCHER;
          }
          else if (t[0] == '9')
-            sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON;
+            sv_player->u.v.items = (int)sv_player->u.v.items | HIT_LASER_CANNON;
          else if (t[0] == '0')
-            sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR;
+            sv_player->u.v.items = (int)sv_player->u.v.items | HIT_MJOLNIR;
          else if (t[0] >= '2')
-            sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
+            sv_player->u.v.items = (int)sv_player->u.v.items | (IT_SHOTGUN << (t[0] - '2'));
       }
       else
       {
          if (t[0] >= '2')
-            sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
+            sv_player->u.v.items = (int)sv_player->u.v.items | (IT_SHOTGUN << (t[0] - '2'));
       }
 		break;
-	
+
     case 's':
 		if (rogue)
 		{
@@ -1575,8 +1582,8 @@
 			    val->_float = v;
 		}
 
-        sv_player->v.ammo_shells = v;
-        break;		
+        sv_player->u.v.ammo_shells = v;
+        break;
     case 'n':
 		if (rogue)
 		{
@@ -1584,15 +1591,15 @@
 			if (val)
 			{
 				val->_float = v;
-				if (sv_player->v.weapon <= IT_LIGHTNING)
-					sv_player->v.ammo_nails = v;
+				if (sv_player->u.v.weapon <= IT_LIGHTNING)
+					sv_player->u.v.ammo_nails = v;
 			}
 		}
 		else
 		{
-			sv_player->v.ammo_nails = v;
+			sv_player->u.v.ammo_nails = v;
 		}
-        break;		
+        break;
     case 'l':
 		if (rogue)
 		{
@@ -1600,8 +1607,8 @@
 			if (val)
 			{
 				val->_float = v;
-				if (sv_player->v.weapon > IT_LIGHTNING)
-					sv_player->v.ammo_nails = v;
+				if (sv_player->u.v.weapon > IT_LIGHTNING)
+					sv_player->u.v.ammo_nails = v;
 			}
 		}
         break;
@@ -1612,15 +1619,15 @@
 			if (val)
 			{
 				val->_float = v;
-				if (sv_player->v.weapon <= IT_LIGHTNING)
-					sv_player->v.ammo_rockets = v;
+				if (sv_player->u.v.weapon <= IT_LIGHTNING)
+					sv_player->u.v.ammo_rockets = v;
 			}
 		}
 		else
 		{
-			sv_player->v.ammo_rockets = v;
+			sv_player->u.v.ammo_rockets = v;
 		}
-        break;		
+        break;
     case 'm':
 		if (rogue)
 		{
@@ -1628,14 +1635,14 @@
 			if (val)
 			{
 				val->_float = v;
-				if (sv_player->v.weapon > IT_LIGHTNING)
-					sv_player->v.ammo_rockets = v;
+				if (sv_player->u.v.weapon > IT_LIGHTNING)
+					sv_player->u.v.ammo_rockets = v;
 			}
 		}
-        break;		
+        break;
     case 'h':
-        sv_player->v.health = v;
-        break;		
+        sv_player->u.v.health = v;
+        break;
     case 'c':
 		if (rogue)
 		{
@@ -1643,15 +1650,15 @@
 			if (val)
 			{
 				val->_float = v;
-				if (sv_player->v.weapon <= IT_LIGHTNING)
-					sv_player->v.ammo_cells = v;
+				if (sv_player->u.v.weapon <= IT_LIGHTNING)
+					sv_player->u.v.ammo_cells = v;
 			}
 		}
 		else
 		{
-			sv_player->v.ammo_cells = v;
+			sv_player->u.v.ammo_cells = v;
 		}
-        break;		
+        break;
     case 'p':
 		if (rogue)
 		{
@@ -1659,11 +1666,11 @@
 			if (val)
 			{
 				val->_float = v;
-				if (sv_player->v.weapon > IT_LIGHTNING)
-					sv_player->v.ammo_cells = v;
+				if (sv_player->u.v.weapon > IT_LIGHTNING)
+					sv_player->u.v.ammo_cells = v;
 			}
 		}
-        break;		
+        break;
     }
 }
 
@@ -1671,11 +1678,11 @@
 {
 	int		i;
 	edict_t	*e;
-	
+
 	for (i=0 ; i<sv.num_edicts ; i++)
 	{
 		e = EDICT_NUM(i);
-		if ( !strcmp (pr_strings + e->v.classname, "viewthing") )
+		if ( !strcmp (pr_strings + e->u.v.classname, "viewthing") )
 			return e;
 	}
 	Con_Printf ("No viewthing on map\n");
@@ -1702,9 +1709,9 @@
 		Con_Printf ("Can't load %s\n", Cmd_Argv(1));
 		return;
 	}
-	
-	e->v.frame = 0;
-	cl.model_precache[(int)e->v.modelindex] = m;
+
+	e->u.v.frame = 0;
+	cl.model_precache[(int)e->u.v.modelindex] = m;
 }
 
 /*
@@ -1721,13 +1728,13 @@
 	e = FindViewthing ();
 	if (!e)
 		return;
-	m = cl.model_precache[(int)e->v.modelindex];
+	m = cl.model_precache[(int)e->u.v.modelindex];
 
 	f = atoi(Cmd_Argv(1));
 	if (f >= m->numframes)
 		f = m->numframes-1;
 
-	e->v.frame = f;		
+	e->u.v.frame = f;
 }
 
 
@@ -1740,7 +1747,7 @@
 	if (!hdr)
 		return;
 	pframedesc = &hdr->frames[frame];
-	
+
 	Con_Printf ("frame %i: %s\n", frame, pframedesc->name);
 }
 
@@ -1753,17 +1760,17 @@
 {
 	edict_t	*e;
 	model_t	*m;
-	
+
 	e = FindViewthing ();
 	if (!e)
 		return;
-	m = cl.model_precache[(int)e->v.modelindex];
+	m = cl.model_precache[(int)e->u.v.modelindex];
 
-	e->v.frame = e->v.frame + 1;
-	if (e->v.frame >= m->numframes)
-		e->v.frame = m->numframes - 1;
+	e->u.v.frame = e->u.v.frame + 1;
+	if (e->u.v.frame >= m->numframes)
+		e->u.v.frame = m->numframes - 1;
 
-	PrintFrameName (m, e->v.frame);		
+	PrintFrameName (m, (int) e->u.v.frame);
 }
 
 /*
@@ -1780,13 +1787,13 @@
 	if (!e)
 		return;
 
-	m = cl.model_precache[(int)e->v.modelindex];
+	m = cl.model_precache[(int)e->u.v.modelindex];
 
-	e->v.frame = e->v.frame - 1;
-	if (e->v.frame < 0)
-		e->v.frame = 0;
+	e->u.v.frame = e->u.v.frame - 1;
+	if (e->u.v.frame < 0)
+		e->u.v.frame = 0;
 
-	PrintFrameName (m, e->v.frame);		
+	PrintFrameName (m, (int) e->u.v.frame);
 }
 
 /*
diff --git a/quake/src/WinQuake/in_dos.c b/quake/src/WinQuake/in_dos.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/in_dos.c
rename to quake/src/WinQuake/in_dos.cpp
diff --git a/quake/src/WinQuake/in_null.c b/quake/src/WinQuake/in_null.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/in_null.c
rename to quake/src/WinQuake/in_null.cpp
diff --git a/quake/src/WinQuake/in_sun.c b/quake/src/WinQuake/in_sun.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/in_sun.c
rename to quake/src/WinQuake/in_sun.cpp
diff --git a/quake/src/WinQuake/in_win.c b/quake/src/WinQuake/in_win.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/in_win.c
rename to quake/src/WinQuake/in_win.cpp
diff --git a/quake/src/WinQuake/keys.c b/quake/src/WinQuake/keys.cpp
old mode 100644
new mode 100755
similarity index 90%
rename from quake/src/WinQuake/keys.c
rename to quake/src/WinQuake/keys.cpp
index 5534056..106bbeb
--- a/quake/src/WinQuake/keys.c
+++ b/quake/src/WinQuake/keys.cpp
@@ -1,759 +1,759 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-#include "quakedef.h"

-

-/*

-

-key up events are sent even if in console mode

-

-*/

-

-

-#define		MAXCMDLINE	256

-char	key_lines[32][MAXCMDLINE];

-int		key_linepos;

-int		shift_down=false;

-int		key_lastpress;

-

-int		edit_line=0;

-int		history_line=0;

-

-keydest_t	key_dest;

-

-int		key_count;			// incremented every key event

-

-char	*keybindings[256];

-qboolean	consolekeys[256];	// if true, can't be rebound while in console

-qboolean	menubound[256];	// if true, can't be rebound while in menu

-int		keyshift[256];		// key to map to if shift held down in console

-int		key_repeats[256];	// if > 1, it is autorepeating

-qboolean	keydown[256];

-

-typedef struct

-{

-	char	*name;

-	int		keynum;

-} keyname_t;

-

-keyname_t keynames[] =

-{

-	{"TAB", K_TAB},

-	{"ENTER", K_ENTER},

-	{"ESCAPE", K_ESCAPE},

-	{"SPACE", K_SPACE},

-	{"BACKSPACE", K_BACKSPACE},

-	{"UPARROW", K_UPARROW},

-	{"DOWNARROW", K_DOWNARROW},

-	{"LEFTARROW", K_LEFTARROW},

-	{"RIGHTARROW", K_RIGHTARROW},

-

-	{"ALT", K_ALT},

-	{"CTRL", K_CTRL},

-	{"SHIFT", K_SHIFT},

-	

-	{"F1", K_F1},

-	{"F2", K_F2},

-	{"F3", K_F3},

-	{"F4", K_F4},

-	{"F5", K_F5},

-	{"F6", K_F6},

-	{"F7", K_F7},

-	{"F8", K_F8},

-	{"F9", K_F9},

-	{"F10", K_F10},

-	{"F11", K_F11},

-	{"F12", K_F12},

-

-	{"INS", K_INS},

-	{"DEL", K_DEL},

-	{"PGDN", K_PGDN},

-	{"PGUP", K_PGUP},

-	{"HOME", K_HOME},

-	{"END", K_END},

-

-	{"MOUSE1", K_MOUSE1},

-	{"MOUSE2", K_MOUSE2},

-	{"MOUSE3", K_MOUSE3},

-

-	{"JOY1", K_JOY1},

-	{"JOY2", K_JOY2},

-	{"JOY3", K_JOY3},

-	{"JOY4", K_JOY4},

-

-	{"AUX1", K_AUX1},

-	{"AUX2", K_AUX2},

-	{"AUX3", K_AUX3},

-	{"AUX4", K_AUX4},

-	{"AUX5", K_AUX5},

-	{"AUX6", K_AUX6},

-	{"AUX7", K_AUX7},

-	{"AUX8", K_AUX8},

-	{"AUX9", K_AUX9},

-	{"AUX10", K_AUX10},

-	{"AUX11", K_AUX11},

-	{"AUX12", K_AUX12},

-	{"AUX13", K_AUX13},

-	{"AUX14", K_AUX14},

-	{"AUX15", K_AUX15},

-	{"AUX16", K_AUX16},

-	{"AUX17", K_AUX17},

-	{"AUX18", K_AUX18},

-	{"AUX19", K_AUX19},

-	{"AUX20", K_AUX20},

-	{"AUX21", K_AUX21},

-	{"AUX22", K_AUX22},

-	{"AUX23", K_AUX23},

-	{"AUX24", K_AUX24},

-	{"AUX25", K_AUX25},

-	{"AUX26", K_AUX26},

-	{"AUX27", K_AUX27},

-	{"AUX28", K_AUX28},

-	{"AUX29", K_AUX29},

-	{"AUX30", K_AUX30},

-	{"AUX31", K_AUX31},

-	{"AUX32", K_AUX32},

-

-	{"PAUSE", K_PAUSE},

-

-	{"MWHEELUP", K_MWHEELUP},

-	{"MWHEELDOWN", K_MWHEELDOWN},

-

-	{"SEMICOLON", ';'},	// because a raw semicolon seperates commands

-

-	{NULL,0}

-};

-

-/*

-==============================================================================

-

-			LINE TYPING INTO THE CONSOLE

-

-==============================================================================

-*/

-

-

-/*

-====================

-Key_Console

-

-Interactive line editing and console scrollback

-====================

-*/

-void Key_Console (int key)

-{

-	char	*cmd;

-	

-	if (key == K_ENTER)

-	{

-		Cbuf_AddText (key_lines[edit_line]+1);	// skip the >

-		Cbuf_AddText ("\n");

-		Con_Printf ("%s\n",key_lines[edit_line]);

-		edit_line = (edit_line + 1) & 31;

-		history_line = edit_line;

-		key_lines[edit_line][0] = ']';

-		key_linepos = 1;

-		if (cls.state == ca_disconnected)

-			SCR_UpdateScreen ();	// force an update, because the command

-									// may take some time

-		return;

-	}

-

-	if (key == K_TAB)

-	{	// command completion

-		cmd = Cmd_CompleteCommand (key_lines[edit_line]+1);

-		if (!cmd)

-			cmd = Cvar_CompleteVariable (key_lines[edit_line]+1);

-		if (cmd)

-		{

-			Q_strcpy (key_lines[edit_line]+1, cmd);

-			key_linepos = Q_strlen(cmd)+1;

-			key_lines[edit_line][key_linepos] = ' ';

-			key_linepos++;

-			key_lines[edit_line][key_linepos] = 0;

-			return;

-		}

-	}

-	

-	if (key == K_BACKSPACE || key == K_LEFTARROW)

-	{

-		if (key_linepos > 1)

-			key_linepos--;

-		return;

-	}

-

-	if (key == K_UPARROW)

-	{

-		do

-		{

-			history_line = (history_line - 1) & 31;

-		} while (history_line != edit_line

-				&& !key_lines[history_line][1]);

-		if (history_line == edit_line)

-			history_line = (edit_line+1)&31;

-		Q_strcpy(key_lines[edit_line], key_lines[history_line]);

-		key_linepos = Q_strlen(key_lines[edit_line]);

-		return;

-	}

-

-	if (key == K_DOWNARROW)

-	{

-		if (history_line == edit_line) return;

-		do

-		{

-			history_line = (history_line + 1) & 31;

-		}

-		while (history_line != edit_line

-			&& !key_lines[history_line][1]);

-		if (history_line == edit_line)

-		{

-			key_lines[edit_line][0] = ']';

-			key_linepos = 1;

-		}

-		else

-		{

-			Q_strcpy(key_lines[edit_line], key_lines[history_line]);

-			key_linepos = Q_strlen(key_lines[edit_line]);

-		}

-		return;

-	}

-

-	if (key == K_PGUP || key==K_MWHEELUP)

-	{

-		con_backscroll += 2;

-		if (con_backscroll > con_totallines - (vid.height>>3) - 1)

-			con_backscroll = con_totallines - (vid.height>>3) - 1;

-		return;

-	}

-

-	if (key == K_PGDN || key==K_MWHEELDOWN)

-	{

-		con_backscroll -= 2;

-		if (con_backscroll < 0)

-			con_backscroll = 0;

-		return;

-	}

-

-	if (key == K_HOME)

-	{

-		con_backscroll = con_totallines - (vid.height>>3) - 1;

-		return;

-	}

-

-	if (key == K_END)

-	{

-		con_backscroll = 0;

-		return;

-	}

-	

-	if (key < 32 || key > 127)

-		return;	// non printable

-		

-	if (key_linepos < MAXCMDLINE-1)

-	{

-		key_lines[edit_line][key_linepos] = key;

-		key_linepos++;

-		key_lines[edit_line][key_linepos] = 0;

-	}

-

-}

-

-//============================================================================

-

-char chat_buffer[32];

-qboolean team_message = false;

-

-void Key_Message (int key)

-{

-	static int chat_bufferlen = 0;

-

-	if (key == K_ENTER)

-	{

-		if (team_message)

-			Cbuf_AddText ("say_team \"");

-		else

-			Cbuf_AddText ("say \"");

-		Cbuf_AddText(chat_buffer);

-		Cbuf_AddText("\"\n");

-

-		key_dest = key_game;

-		chat_bufferlen = 0;

-		chat_buffer[0] = 0;

-		return;

-	}

-

-	if (key == K_ESCAPE)

-	{

-		key_dest = key_game;

-		chat_bufferlen = 0;

-		chat_buffer[0] = 0;

-		return;

-	}

-

-	if (key < 32 || key > 127)

-		return;	// non printable

-

-	if (key == K_BACKSPACE)

-	{

-		if (chat_bufferlen)

-		{

-			chat_bufferlen--;

-			chat_buffer[chat_bufferlen] = 0;

-		}

-		return;

-	}

-

-	if (chat_bufferlen == 31)

-		return; // all full

-

-	chat_buffer[chat_bufferlen++] = key;

-	chat_buffer[chat_bufferlen] = 0;

-}

-

-//============================================================================

-

-

-/*

-===================

-Key_StringToKeynum

-

-Returns a key number to be used to index keybindings[] by looking at

-the given string.  Single ascii characters return themselves, while

-the K_* names are matched up.

-===================

-*/

-int Key_StringToKeynum (char *str)

-{

-	keyname_t	*kn;

-	

-	if (!str || !str[0])

-		return -1;

-	if (!str[1])

-		return str[0];

-

-	for (kn=keynames ; kn->name ; kn++)

-	{

-		if (!Q_strcasecmp(str,kn->name))

-			return kn->keynum;

-	}

-	return -1;

-}

-

-/*

-===================

-Key_KeynumToString

-

-Returns a string (either a single ascii char, or a K_* name) for the

-given keynum.

-FIXME: handle quote special (general escape sequence?)

-===================

-*/

-char *Key_KeynumToString (int keynum)

-{

-	keyname_t	*kn;	

-	static	char	tinystr[2];

-	

-	if (keynum == -1)

-		return "<KEY NOT FOUND>";

-	if (keynum > 32 && keynum < 127)

-	{	// printable ascii

-		tinystr[0] = keynum;

-		tinystr[1] = 0;

-		return tinystr;

-	}

-	

-	for (kn=keynames ; kn->name ; kn++)

-		if (keynum == kn->keynum)

-			return kn->name;

-

-	return "<UNKNOWN KEYNUM>";

-}

-

-

-/*

-===================

-Key_SetBinding

-===================

-*/

-void Key_SetBinding (int keynum, char *binding)

-{

-	char	*new;

-	int		l;

-			

-	if (keynum == -1)

-		return;

-

-// free old bindings

-	if (keybindings[keynum])

-	{

-		Z_Free (keybindings[keynum]);

-		keybindings[keynum] = NULL;

-	}

-			

-// allocate memory for new binding

-	l = Q_strlen (binding);	

-	new = Z_Malloc (l+1);

-	Q_strcpy (new, binding);

-	new[l] = 0;

-	keybindings[keynum] = new;	

-}

-

-/*

-===================

-Key_Unbind_f

-===================

-*/

-void Key_Unbind_f (void)

-{

-	int		b;

-

-	if (Cmd_Argc() != 2)

-	{

-		Con_Printf ("unbind <key> : remove commands from a key\n");

-		return;

-	}

-	

-	b = Key_StringToKeynum (Cmd_Argv(1));

-	if (b==-1)

-	{

-		Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));

-		return;

-	}

-

-	Key_SetBinding (b, "");

-}

-

-void Key_Unbindall_f (void)

-{

-	int		i;

-	

-	for (i=0 ; i<256 ; i++)

-		if (keybindings[i])

-			Key_SetBinding (i, "");

-}

-

-

-/*

-===================

-Key_Bind_f

-===================

-*/

-void Key_Bind_f (void)

-{

-	int			i, c, b;

-	char		cmd[1024];

-	

-	c = Cmd_Argc();

-

-	if (c != 2 && c != 3)

-	{

-		Con_Printf ("bind <key> [command] : attach a command to a key\n");

-		return;

-	}

-	b = Key_StringToKeynum (Cmd_Argv(1));

-	if (b==-1)

-	{

-		Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));

-		return;

-	}

-

-	if (c == 2)

-	{

-		if (keybindings[b])

-			Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );

-		else

-			Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );

-		return;

-	}

-	

-// copy the rest of the command line

-	cmd[0] = 0;		// start out with a null string

-	for (i=2 ; i< c ; i++)

-	{

-		if (i > 2)

-			strcat (cmd, " ");

-		strcat (cmd, Cmd_Argv(i));

-	}

-

-	Key_SetBinding (b, cmd);

-}

-

-/*

-============

-Key_WriteBindings

-

-Writes lines containing "bind key value"

-============

-*/

-void Key_WriteBindings (FILE *f)

-{

-	int		i;

-

-	for (i=0 ; i<256 ; i++)

-		if (keybindings[i])

-			if (*keybindings[i])

-				fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]);

-}

-

-

-/*

-===================

-Key_Init

-===================

-*/

-void Key_Init (void)

-{

-	int		i;

-

-	for (i=0 ; i<32 ; i++)

-	{

-		key_lines[i][0] = ']';

-		key_lines[i][1] = 0;

-	}

-	key_linepos = 1;

-	

-//

-// init ascii characters in console mode

-//

-	for (i=32 ; i<128 ; i++)

-		consolekeys[i] = true;

-	consolekeys[K_ENTER] = true;

-	consolekeys[K_TAB] = true;

-	consolekeys[K_LEFTARROW] = true;

-	consolekeys[K_RIGHTARROW] = true;

-	consolekeys[K_UPARROW] = true;

-	consolekeys[K_DOWNARROW] = true;

-	consolekeys[K_BACKSPACE] = true;

-	consolekeys[K_PGUP] = true;

-	consolekeys[K_PGDN] = true;

-	consolekeys[K_SHIFT] = true;

-	consolekeys[K_MWHEELUP] = true;

-	consolekeys[K_MWHEELDOWN] = true;

-	consolekeys['`'] = false;

-	consolekeys['~'] = false;

-

-	for (i=0 ; i<256 ; i++)

-		keyshift[i] = i;

-	for (i='a' ; i<='z' ; i++)

-		keyshift[i] = i - 'a' + 'A';

-	keyshift['1'] = '!';

-	keyshift['2'] = '@';

-	keyshift['3'] = '#';

-	keyshift['4'] = '$';

-	keyshift['5'] = '%';

-	keyshift['6'] = '^';

-	keyshift['7'] = '&';

-	keyshift['8'] = '*';

-	keyshift['9'] = '(';

-	keyshift['0'] = ')';

-	keyshift['-'] = '_';

-	keyshift['='] = '+';

-	keyshift[','] = '<';

-	keyshift['.'] = '>';

-	keyshift['/'] = '?';

-	keyshift[';'] = ':';

-	keyshift['\''] = '"';

-	keyshift['['] = '{';

-	keyshift[']'] = '}';

-	keyshift['`'] = '~';

-	keyshift['\\'] = '|';

-

-	menubound[K_ESCAPE] = true;

-	for (i=0 ; i<12 ; i++)

-		menubound[K_F1+i] = true;

-

-//

-// register our functions

-//

-	Cmd_AddCommand ("bind",Key_Bind_f);

-	Cmd_AddCommand ("unbind",Key_Unbind_f);

-	Cmd_AddCommand ("unbindall",Key_Unbindall_f);

-

-

-}

-

-/*

-===================

-Key_Event

-

-Called by the system between frames for both key up and key down events

-Should NOT be called during an interrupt!

-===================

-*/

-void Key_Event (int key, qboolean down)

-{

-	char	*kb;

-	char	cmd[1024];

-

-	keydown[key] = down;

-

-	if (!down)

-		key_repeats[key] = 0;

-

-	key_lastpress = key;

-	key_count++;

-	if (key_count <= 0)

-	{

-		return;		// just catching keys for Con_NotifyBox

-	}

-

-// update auto-repeat status

-	if (down)

-	{

-		key_repeats[key]++;

-		if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1)

-		{

-			return;	// ignore most autorepeats

-		}

-			

-		if (key >= 200 && !keybindings[key])

-			Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );

-	}

-

-	if (key == K_SHIFT)

-		shift_down = down;

-

-//

-// handle escape specialy, so the user can never unbind it

-//

-	if (key == K_ESCAPE)

-	{

-		if (!down)

-			return;

-		switch (key_dest)

-		{

-		case key_message:

-			Key_Message (key);

-			break;

-		case key_menu:

-			M_Keydown (key);

-			break;

-		case key_game:

-		case key_console:

-			M_ToggleMenu_f ();

-			break;

-		default:

-			Sys_Error ("Bad key_dest");

-		}

-		return;

-	}

-

-//

-// key up events only generate commands if the game key binding is

-// a button command (leading + sign).  These will occur even in console mode,

-// to keep the character from continuing an action started before a console

-// switch.  Button commands include the kenum as a parameter, so multiple

-// downs can be matched with ups

-//

-	if (!down)

-	{

-		kb = keybindings[key];

-		if (kb && kb[0] == '+')

-		{

-			sprintf (cmd, "-%s %i\n", kb+1, key);

-			Cbuf_AddText (cmd);

-		}

-		if (keyshift[key] != key)

-		{

-			kb = keybindings[keyshift[key]];

-			if (kb && kb[0] == '+')

-			{

-				sprintf (cmd, "-%s %i\n", kb+1, key);

-				Cbuf_AddText (cmd);

-			}

-		}

-		return;

-	}

-

-//

-// during demo playback, most keys bring up the main menu

-//

-	if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)

-	{

-		M_ToggleMenu_f ();

-		return;

-	}

-

-//

-// if not a consolekey, send to the interpreter no matter what mode is

-//

-	if ( (key_dest == key_menu && menubound[key])

-	|| (key_dest == key_console && !consolekeys[key])

-	|| (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) )

-	{

-		kb = keybindings[key];

-		if (kb)

-		{

-			if (kb[0] == '+')

-			{	// button commands add keynum as a parm

-				sprintf (cmd, "%s %i\n", kb, key);

-				Cbuf_AddText (cmd);

-			}

-			else

-			{

-				Cbuf_AddText (kb);

-				Cbuf_AddText ("\n");

-			}

-		}

-		return;

-	}

-

-	if (!down)

-		return;		// other systems only care about key down events

-

-	if (shift_down)

-	{

-		key = keyshift[key];

-	}

-

-	switch (key_dest)

-	{

-	case key_message:

-		Key_Message (key);

-		break;

-	case key_menu:

-		M_Keydown (key);

-		break;

-

-	case key_game:

-	case key_console:

-		Key_Console (key);

-		break;

-	default:

-		Sys_Error ("Bad key_dest");

-	}

-}

-

-

-/*

-===================

-Key_ClearStates

-===================

-*/

-void Key_ClearStates (void)

-{

-	int		i;

-

-	for (i=0 ; i<256 ; i++)

-	{

-		keydown[i] = false;

-		key_repeats[i] = 0;

-	}

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "quakedef.h"
+
+/*
+
+key up events are sent even if in console mode
+
+*/
+
+
+#define		MAXCMDLINE	256
+char	key_lines[32][MAXCMDLINE];
+int		key_linepos;
+int		shift_down=false;
+int		key_lastpress;
+
+int		edit_line=0;
+int		history_line=0;
+
+keydest_t	key_dest;
+
+int		key_count;			// incremented every key event
+
+char	*keybindings[256];
+qboolean	consolekeys[256];	// if true, can't be rebound while in console
+qboolean	menubound[256];	// if true, can't be rebound while in menu
+int		keyshift[256];		// key to map to if shift held down in console
+int		key_repeats[256];	// if > 1, it is autorepeating
+qboolean	keydown[256];
+
+typedef struct
+{
+	const char	*name;
+	int		keynum;
+} keyname_t;
+
+keyname_t keynames[] =
+{
+	{"TAB", K_TAB},
+	{"ENTER", K_ENTER},
+	{"ESCAPE", K_ESCAPE},
+	{"SPACE", K_SPACE},
+	{"BACKSPACE", K_BACKSPACE},
+	{"UPARROW", K_UPARROW},
+	{"DOWNARROW", K_DOWNARROW},
+	{"LEFTARROW", K_LEFTARROW},
+	{"RIGHTARROW", K_RIGHTARROW},
+
+	{"ALT", K_ALT},
+	{"CTRL", K_CTRL},
+	{"SHIFT", K_SHIFT},
+	
+	{"F1", K_F1},
+	{"F2", K_F2},
+	{"F3", K_F3},
+	{"F4", K_F4},
+	{"F5", K_F5},
+	{"F6", K_F6},
+	{"F7", K_F7},
+	{"F8", K_F8},
+	{"F9", K_F9},
+	{"F10", K_F10},
+	{"F11", K_F11},
+	{"F12", K_F12},
+
+	{"INS", K_INS},
+	{"DEL", K_DEL},
+	{"PGDN", K_PGDN},
+	{"PGUP", K_PGUP},
+	{"HOME", K_HOME},
+	{"END", K_END},
+
+	{"MOUSE1", K_MOUSE1},
+	{"MOUSE2", K_MOUSE2},
+	{"MOUSE3", K_MOUSE3},
+
+	{"JOY1", K_JOY1},
+	{"JOY2", K_JOY2},
+	{"JOY3", K_JOY3},
+	{"JOY4", K_JOY4},
+
+	{"AUX1", K_AUX1},
+	{"AUX2", K_AUX2},
+	{"AUX3", K_AUX3},
+	{"AUX4", K_AUX4},
+	{"AUX5", K_AUX5},
+	{"AUX6", K_AUX6},
+	{"AUX7", K_AUX7},
+	{"AUX8", K_AUX8},
+	{"AUX9", K_AUX9},
+	{"AUX10", K_AUX10},
+	{"AUX11", K_AUX11},
+	{"AUX12", K_AUX12},
+	{"AUX13", K_AUX13},
+	{"AUX14", K_AUX14},
+	{"AUX15", K_AUX15},
+	{"AUX16", K_AUX16},
+	{"AUX17", K_AUX17},
+	{"AUX18", K_AUX18},
+	{"AUX19", K_AUX19},
+	{"AUX20", K_AUX20},
+	{"AUX21", K_AUX21},
+	{"AUX22", K_AUX22},
+	{"AUX23", K_AUX23},
+	{"AUX24", K_AUX24},
+	{"AUX25", K_AUX25},
+	{"AUX26", K_AUX26},
+	{"AUX27", K_AUX27},
+	{"AUX28", K_AUX28},
+	{"AUX29", K_AUX29},
+	{"AUX30", K_AUX30},
+	{"AUX31", K_AUX31},
+	{"AUX32", K_AUX32},
+
+	{"PAUSE", K_PAUSE},
+
+	{"MWHEELUP", K_MWHEELUP},
+	{"MWHEELDOWN", K_MWHEELDOWN},
+
+	{"SEMICOLON", ';'},	// because a raw semicolon seperates commands
+
+	{NULL,0}
+};
+
+/*
+==============================================================================
+
+			LINE TYPING INTO THE CONSOLE
+
+==============================================================================
+*/
+
+
+/*
+====================
+Key_Console
+
+Interactive line editing and console scrollback
+====================
+*/
+void Key_Console (int key)
+{
+	const char	*cmd;
+	
+	if (key == K_ENTER)
+	{
+		Cbuf_AddText (key_lines[edit_line]+1);	// skip the >
+		Cbuf_AddText ("\n");
+		Con_Printf ("%s\n",key_lines[edit_line]);
+		edit_line = (edit_line + 1) & 31;
+		history_line = edit_line;
+		key_lines[edit_line][0] = ']';
+		key_linepos = 1;
+		if (cls.state == ca_disconnected)
+			SCR_UpdateScreen ();	// force an update, because the command
+									// may take some time
+		return;
+	}
+
+	if (key == K_TAB)
+	{	// command completion
+		cmd = Cmd_CompleteCommand (key_lines[edit_line]+1);
+		if (!cmd)
+			cmd = Cvar_CompleteVariable (key_lines[edit_line]+1);
+		if (cmd)
+		{
+			Q_strcpy (key_lines[edit_line]+1, cmd);
+			key_linepos = Q_strlen(cmd)+1;
+			key_lines[edit_line][key_linepos] = ' ';
+			key_linepos++;
+			key_lines[edit_line][key_linepos] = 0;
+			return;
+		}
+	}
+	
+	if (key == K_BACKSPACE || key == K_LEFTARROW)
+	{
+		if (key_linepos > 1)
+			key_linepos--;
+		return;
+	}
+
+	if (key == K_UPARROW)
+	{
+		do
+		{
+			history_line = (history_line - 1) & 31;
+		} while (history_line != edit_line
+				&& !key_lines[history_line][1]);
+		if (history_line == edit_line)
+			history_line = (edit_line+1)&31;
+		Q_strcpy(key_lines[edit_line], key_lines[history_line]);
+		key_linepos = Q_strlen(key_lines[edit_line]);
+		return;
+	}
+
+	if (key == K_DOWNARROW)
+	{
+		if (history_line == edit_line) return;
+		do
+		{
+			history_line = (history_line + 1) & 31;
+		}
+		while (history_line != edit_line
+			&& !key_lines[history_line][1]);
+		if (history_line == edit_line)
+		{
+			key_lines[edit_line][0] = ']';
+			key_linepos = 1;
+		}
+		else
+		{
+			Q_strcpy(key_lines[edit_line], key_lines[history_line]);
+			key_linepos = Q_strlen(key_lines[edit_line]);
+		}
+		return;
+	}
+
+	if (key == K_PGUP || key==K_MWHEELUP)
+	{
+		con_backscroll += 2;
+		if (con_backscroll > (int)(con_totallines - (vid.height>>3) - 1))
+			con_backscroll = (int)(con_totallines - (vid.height>>3) - 1);
+		return;
+	}
+
+	if (key == K_PGDN || key==K_MWHEELDOWN)
+	{
+		con_backscroll -= 2;
+		if (con_backscroll < 0)
+			con_backscroll = 0;
+		return;
+	}
+
+	if (key == K_HOME)
+	{
+		con_backscroll = con_totallines - (vid.height>>3) - 1;
+		return;
+	}
+
+	if (key == K_END)
+	{
+		con_backscroll = 0;
+		return;
+	}
+	
+	if (key < 32 || key > 127)
+		return;	// non printable
+		
+	if (key_linepos < MAXCMDLINE-1)
+	{
+		key_lines[edit_line][key_linepos] = key;
+		key_linepos++;
+		key_lines[edit_line][key_linepos] = 0;
+	}
+
+}
+
+//============================================================================
+
+char chat_buffer[32];
+qboolean team_message = false;
+
+void Key_Message (int key)
+{
+	static int chat_bufferlen = 0;
+
+	if (key == K_ENTER)
+	{
+		if (team_message)
+			Cbuf_AddText ("say_team \"");
+		else
+			Cbuf_AddText ("say \"");
+		Cbuf_AddText(chat_buffer);
+		Cbuf_AddText("\"\n");
+
+		key_dest = key_game;
+		chat_bufferlen = 0;
+		chat_buffer[0] = 0;
+		return;
+	}
+
+	if (key == K_ESCAPE)
+	{
+		key_dest = key_game;
+		chat_bufferlen = 0;
+		chat_buffer[0] = 0;
+		return;
+	}
+
+	if (key < 32 || key > 127)
+		return;	// non printable
+
+	if (key == K_BACKSPACE)
+	{
+		if (chat_bufferlen)
+		{
+			chat_bufferlen--;
+			chat_buffer[chat_bufferlen] = 0;
+		}
+		return;
+	}
+
+	if (chat_bufferlen == 31)
+		return; // all full
+
+	chat_buffer[chat_bufferlen++] = key;
+	chat_buffer[chat_bufferlen] = 0;
+}
+
+//============================================================================
+
+
+/*
+===================
+Key_StringToKeynum
+
+Returns a key number to be used to index keybindings[] by looking at
+the given string.  Single ascii characters return themselves, while
+the K_* names are matched up.
+===================
+*/
+int Key_StringToKeynum (char *str)
+{
+	keyname_t	*kn;
+	
+	if (!str || !str[0])
+		return -1;
+	if (!str[1])
+		return str[0];
+
+	for (kn=keynames ; kn->name ; kn++)
+	{
+		if (!Q_strcasecmp(str,kn->name))
+			return kn->keynum;
+	}
+	return -1;
+}
+
+/*
+===================
+Key_KeynumToString
+
+Returns a string (either a single ascii char, or a K_* name) for the
+given keynum.
+FIXME: handle quote special (general escape sequence?)
+===================
+*/
+const char *Key_KeynumToString (int keynum)
+{
+	keyname_t	*kn;	
+	static	char	tinystr[2];
+	
+	if (keynum == -1)
+		return "<KEY NOT FOUND>";
+	if (keynum > 32 && keynum < 127)
+	{	// printable ascii
+		tinystr[0] = keynum;
+		tinystr[1] = 0;
+		return tinystr;
+	}
+	
+	for (kn=keynames ; kn->name ; kn++)
+		if (keynum == kn->keynum)
+			return kn->name;
+
+	return "<UNKNOWN KEYNUM>";
+}
+
+
+/*
+===================
+Key_SetBinding
+===================
+*/
+void Key_SetBinding (int keynum, const char *binding)
+{
+	char	*newKey;
+	int		l;
+			
+	if (keynum == -1)
+		return;
+
+// free old bindings
+	if (keybindings[keynum])
+	{
+		Z_Free (keybindings[keynum]);
+		keybindings[keynum] = NULL;
+	}
+			
+// allocate memory for new binding
+	l = Q_strlen (binding);	
+	newKey = (char*) Z_Malloc (l+1);
+	Q_strcpy (newKey, binding);
+	newKey[l] = 0;
+	keybindings[keynum] = newKey;	
+}
+
+/*
+===================
+Key_Unbind_f
+===================
+*/
+void Key_Unbind_f (void)
+{
+	int		b;
+
+	if (Cmd_Argc() != 2)
+	{
+		Con_Printf ("unbind <key> : remove commands from a key\n");
+		return;
+	}
+	
+	b = Key_StringToKeynum (Cmd_Argv(1));
+	if (b==-1)
+	{
+		Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+		return;
+	}
+
+	Key_SetBinding (b, "");
+}
+
+void Key_Unbindall_f (void)
+{
+	int		i;
+	
+	for (i=0 ; i<256 ; i++)
+		if (keybindings[i])
+			Key_SetBinding (i, "");
+}
+
+
+/*
+===================
+Key_Bind_f
+===================
+*/
+void Key_Bind_f (void)
+{
+	int			i, c, b;
+	char		cmd[1024];
+	
+	c = Cmd_Argc();
+
+	if (c != 2 && c != 3)
+	{
+		Con_Printf ("bind <key> [command] : attach a command to a key\n");
+		return;
+	}
+	b = Key_StringToKeynum (Cmd_Argv(1));
+	if (b==-1)
+	{
+		Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+		return;
+	}
+
+	if (c == 2)
+	{
+		if (keybindings[b])
+			Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
+		else
+			Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
+		return;
+	}
+	
+// copy the rest of the command line
+	cmd[0] = 0;		// start out with a null string
+	for (i=2 ; i< c ; i++)
+	{
+		if (i > 2)
+			strcat (cmd, " ");
+		strcat (cmd, Cmd_Argv(i));
+	}
+
+	Key_SetBinding (b, cmd);
+}
+
+/*
+============
+Key_WriteBindings
+
+Writes lines containing "bind key value"
+============
+*/
+void Key_WriteBindings (FILE *f)
+{
+	int		i;
+
+	for (i=0 ; i<256 ; i++)
+		if (keybindings[i])
+			if (*keybindings[i])
+				fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+===================
+Key_Init
+===================
+*/
+void Key_Init (void)
+{
+	int		i;
+
+	for (i=0 ; i<32 ; i++)
+	{
+		key_lines[i][0] = ']';
+		key_lines[i][1] = 0;
+	}
+	key_linepos = 1;
+	
+//
+// init ascii characters in console mode
+//
+	for (i=32 ; i<128 ; i++)
+		consolekeys[i] = true;
+	consolekeys[K_ENTER] = true;
+	consolekeys[K_TAB] = true;
+	consolekeys[K_LEFTARROW] = true;
+	consolekeys[K_RIGHTARROW] = true;
+	consolekeys[K_UPARROW] = true;
+	consolekeys[K_DOWNARROW] = true;
+	consolekeys[K_BACKSPACE] = true;
+	consolekeys[K_PGUP] = true;
+	consolekeys[K_PGDN] = true;
+	consolekeys[K_SHIFT] = true;
+	consolekeys[K_MWHEELUP] = true;
+	consolekeys[K_MWHEELDOWN] = true;
+	consolekeys[(unsigned int) '`'] = false;
+	consolekeys[(unsigned int) '~'] = false;
+
+	for (i=0 ; i<256 ; i++)
+		keyshift[i] = i;
+	for (i='a' ; i<='z' ; i++)
+		keyshift[i] = i - 'a' + 'A';
+	keyshift[(unsigned int) '1'] = '!';
+	keyshift[(unsigned int) '2'] = '@';
+	keyshift[(unsigned int) '3'] = '#';
+	keyshift[(unsigned int) '4'] = '$';
+	keyshift[(unsigned int) '5'] = '%';
+	keyshift[(unsigned int) '6'] = '^';
+	keyshift[(unsigned int) '7'] = '&';
+	keyshift[(unsigned int) '8'] = '*';
+	keyshift[(unsigned int) '9'] = '(';
+	keyshift[(unsigned int) '0'] = ')';
+	keyshift[(unsigned int) '-'] = '_';
+	keyshift[(unsigned int) '='] = '+';
+	keyshift[(unsigned int) ','] = '<';
+	keyshift[(unsigned int) '.'] = '>';
+	keyshift[(unsigned int) '/'] = '?';
+	keyshift[(unsigned int) ';'] = ':';
+	keyshift[(unsigned int) '\''] = '"';
+	keyshift[(unsigned int) '['] = '{';
+	keyshift[(unsigned int) ']'] = '}';
+	keyshift[(unsigned int) '`'] = '~';
+	keyshift[(unsigned int) '\\'] = '|';
+
+	menubound[K_ESCAPE] = true;
+	for (i=0 ; i<12 ; i++)
+		menubound[K_F1+i] = true;
+
+//
+// register our functions
+//
+	Cmd_AddCommand ("bind",Key_Bind_f);
+	Cmd_AddCommand ("unbind",Key_Unbind_f);
+	Cmd_AddCommand ("unbindall",Key_Unbindall_f);
+
+
+}
+
+/*
+===================
+Key_Event
+
+Called by the system between frames for both key up and key down events
+Should NOT be called during an interrupt!
+===================
+*/
+void Key_Event (int key, qboolean down)
+{
+	char	*kb;
+	char	cmd[1024];
+
+	keydown[key] = down;
+
+	if (!down)
+		key_repeats[key] = 0;
+
+	key_lastpress = key;
+	key_count++;
+	if (key_count <= 0)
+	{
+		return;		// just catching keys for Con_NotifyBox
+	}
+
+// update auto-repeat status
+	if (down)
+	{
+		key_repeats[key]++;
+		if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1)
+		{
+			return;	// ignore most autorepeats
+		}
+			
+		if (key >= 200 && !keybindings[key])
+			Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
+	}
+
+	if (key == K_SHIFT)
+		shift_down = down;
+
+//
+// handle escape specialy, so the user can never unbind it
+//
+	if (key == K_ESCAPE)
+	{
+		if (!down)
+			return;
+		switch (key_dest)
+		{
+		case key_message:
+			Key_Message (key);
+			break;
+		case key_menu:
+			M_Keydown (key);
+			break;
+		case key_game:
+		case key_console:
+			M_ToggleMenu_f ();
+			break;
+		default:
+			Sys_Error ("Bad key_dest");
+		}
+		return;
+	}
+
+//
+// key up events only generate commands if the game key binding is
+// a button command (leading + sign).  These will occur even in console mode,
+// to keep the character from continuing an action started before a console
+// switch.  Button commands include the kenum as a parameter, so multiple
+// downs can be matched with ups
+//
+	if (!down)
+	{
+		kb = keybindings[key];
+		if (kb && kb[0] == '+')
+		{
+			sprintf (cmd, "-%s %i\n", kb+1, key);
+			Cbuf_AddText (cmd);
+		}
+		if (keyshift[key] != key)
+		{
+			kb = keybindings[keyshift[key]];
+			if (kb && kb[0] == '+')
+			{
+				sprintf (cmd, "-%s %i\n", kb+1, key);
+				Cbuf_AddText (cmd);
+			}
+		}
+		return;
+	}
+
+//
+// during demo playback, most keys bring up the main menu
+//
+	if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)
+	{
+		M_ToggleMenu_f ();
+		return;
+	}
+
+//
+// if not a consolekey, send to the interpreter no matter what mode is
+//
+	if ( (key_dest == key_menu && menubound[key])
+	|| (key_dest == key_console && !consolekeys[key])
+	|| (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) )
+	{
+		kb = keybindings[key];
+		if (kb)
+		{
+			if (kb[0] == '+')
+			{	// button commands add keynum as a parm
+				sprintf (cmd, "%s %i\n", kb, key);
+				Cbuf_AddText (cmd);
+			}
+			else
+			{
+				Cbuf_AddText (kb);
+				Cbuf_AddText ("\n");
+			}
+		}
+		return;
+	}
+
+	if (!down)
+		return;		// other systems only care about key down events
+
+	if (shift_down)
+	{
+		key = keyshift[key];
+	}
+
+	switch (key_dest)
+	{
+	case key_message:
+		Key_Message (key);
+		break;
+	case key_menu:
+		M_Keydown (key);
+		break;
+
+	case key_game:
+	case key_console:
+		Key_Console (key);
+		break;
+	default:
+		Sys_Error ("Bad key_dest");
+	}
+}
+
+
+/*
+===================
+Key_ClearStates
+===================
+*/
+void Key_ClearStates (void)
+{
+	int		i;
+
+	for (i=0 ; i<256 ; i++)
+	{
+		keydown[i] = false;
+		key_repeats[i] = 0;
+	}
+}
+
diff --git a/quake/src/WinQuake/keys.h b/quake/src/WinQuake/keys.h
index 986c9d0..2c12dc6 100644
--- a/quake/src/WinQuake/keys.h
+++ b/quake/src/WinQuake/keys.h
@@ -1,133 +1,133 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-//

-// these are the key numbers that should be passed to Key_Event

-//

-#define	K_TAB			9

-#define	K_ENTER			13

-#define	K_ESCAPE		27

-#define	K_SPACE			32

-

-// normal keys should be passed as lowercased ascii

-

-#define	K_BACKSPACE		127

-#define	K_UPARROW		128

-#define	K_DOWNARROW		129

-#define	K_LEFTARROW		130

-#define	K_RIGHTARROW	131

-

-#define	K_ALT			132

-#define	K_CTRL			133

-#define	K_SHIFT			134

-#define	K_F1			135

-#define	K_F2			136

-#define	K_F3			137

-#define	K_F4			138

-#define	K_F5			139

-#define	K_F6			140

-#define	K_F7			141

-#define	K_F8			142

-#define	K_F9			143

-#define	K_F10			144

-#define	K_F11			145

-#define	K_F12			146

-#define	K_INS			147

-#define	K_DEL			148

-#define	K_PGDN			149

-#define	K_PGUP			150

-#define	K_HOME			151

-#define	K_END			152

-

-#define K_PAUSE			255

-

-//

-// mouse buttons generate virtual keys

-//

-#define	K_MOUSE1		200

-#define	K_MOUSE2		201

-#define	K_MOUSE3		202

-

-//

-// joystick buttons

-//

-#define	K_JOY1			203

-#define	K_JOY2			204

-#define	K_JOY3			205

-#define	K_JOY4			206

-

-//

-// aux keys are for multi-buttoned joysticks to generate so they can use

-// the normal binding process

-//

-#define	K_AUX1			207

-#define	K_AUX2			208

-#define	K_AUX3			209

-#define	K_AUX4			210

-#define	K_AUX5			211

-#define	K_AUX6			212

-#define	K_AUX7			213

-#define	K_AUX8			214

-#define	K_AUX9			215

-#define	K_AUX10			216

-#define	K_AUX11			217

-#define	K_AUX12			218

-#define	K_AUX13			219

-#define	K_AUX14			220

-#define	K_AUX15			221

-#define	K_AUX16			222

-#define	K_AUX17			223

-#define	K_AUX18			224

-#define	K_AUX19			225

-#define	K_AUX20			226

-#define	K_AUX21			227

-#define	K_AUX22			228

-#define	K_AUX23			229

-#define	K_AUX24			230

-#define	K_AUX25			231

-#define	K_AUX26			232

-#define	K_AUX27			233

-#define	K_AUX28			234

-#define	K_AUX29			235

-#define	K_AUX30			236

-#define	K_AUX31			237

-#define	K_AUX32			238

-

-// JACK: Intellimouse(c) Mouse Wheel Support

-

-#define K_MWHEELUP		239

-#define K_MWHEELDOWN	240

-

-

-

-typedef enum {key_game, key_console, key_message, key_menu} keydest_t;

-

-extern keydest_t	key_dest;

-extern char *keybindings[256];

-extern	int		key_repeats[256];

-extern	int		key_count;			// incremented every key event

-extern	int		key_lastpress;

-

-void Key_Event (int key, qboolean down);

-void Key_Init (void);

-void Key_WriteBindings (FILE *f);

-void Key_SetBinding (int keynum, char *binding);

-void Key_ClearStates (void);

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+//
+// these are the key numbers that should be passed to Key_Event
+//
+#define	K_TAB			9
+#define	K_ENTER			13
+#define	K_ESCAPE		27
+#define	K_SPACE			32
+
+// normal keys should be passed as lowercased ascii
+
+#define	K_BACKSPACE		127
+#define	K_UPARROW		128
+#define	K_DOWNARROW		129
+#define	K_LEFTARROW		130
+#define	K_RIGHTARROW	131
+
+#define	K_ALT			132
+#define	K_CTRL			133
+#define	K_SHIFT			134
+#define	K_F1			135
+#define	K_F2			136
+#define	K_F3			137
+#define	K_F4			138
+#define	K_F5			139
+#define	K_F6			140
+#define	K_F7			141
+#define	K_F8			142
+#define	K_F9			143
+#define	K_F10			144
+#define	K_F11			145
+#define	K_F12			146
+#define	K_INS			147
+#define	K_DEL			148
+#define	K_PGDN			149
+#define	K_PGUP			150
+#define	K_HOME			151
+#define	K_END			152
+
+#define K_PAUSE			255
+
+//
+// mouse buttons generate virtual keys
+//
+#define	K_MOUSE1		200
+#define	K_MOUSE2		201
+#define	K_MOUSE3		202
+
+//
+// joystick buttons
+//
+#define	K_JOY1			203
+#define	K_JOY2			204
+#define	K_JOY3			205
+#define	K_JOY4			206
+
+//
+// aux keys are for multi-buttoned joysticks to generate so they can use
+// the normal binding process
+//
+#define	K_AUX1			207
+#define	K_AUX2			208
+#define	K_AUX3			209
+#define	K_AUX4			210
+#define	K_AUX5			211
+#define	K_AUX6			212
+#define	K_AUX7			213
+#define	K_AUX8			214
+#define	K_AUX9			215
+#define	K_AUX10			216
+#define	K_AUX11			217
+#define	K_AUX12			218
+#define	K_AUX13			219
+#define	K_AUX14			220
+#define	K_AUX15			221
+#define	K_AUX16			222
+#define	K_AUX17			223
+#define	K_AUX18			224
+#define	K_AUX19			225
+#define	K_AUX20			226
+#define	K_AUX21			227
+#define	K_AUX22			228
+#define	K_AUX23			229
+#define	K_AUX24			230
+#define	K_AUX25			231
+#define	K_AUX26			232
+#define	K_AUX27			233
+#define	K_AUX28			234
+#define	K_AUX29			235
+#define	K_AUX30			236
+#define	K_AUX31			237
+#define	K_AUX32			238
+
+// JACK: Intellimouse(c) Mouse Wheel Support
+
+#define K_MWHEELUP		239
+#define K_MWHEELDOWN	240
+
+
+
+typedef enum {key_game, key_console, key_message, key_menu, keydest_t_max = 1 << 30} keydest_t;
+
+extern keydest_t	key_dest;
+extern char *keybindings[256];
+extern	int		key_repeats[256];
+extern	int		key_count;			// incremented every key event
+extern	int		key_lastpress;
+
+void Key_Event (int key, qboolean down);
+void Key_Init (void);
+void Key_WriteBindings (FILE *f);
+void Key_SetBinding (int keynum, const char *binding);
+void Key_ClearStates (void);
+
diff --git a/quake/src/WinQuake/kit/GLQUAKE.EXE b/quake/src/WinQuake/kit/GLQUAKE.EXE
old mode 100755
new mode 100644
Binary files differ
diff --git a/quake/src/WinQuake/main.cpp b/quake/src/WinQuake/main.cpp
new file mode 100644
index 0000000..7c0763c
--- /dev/null
+++ b/quake/src/WinQuake/main.cpp
@@ -0,0 +1,123 @@
+/* //device/apps/Quake/quake/src/QW/client/main.c
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <assert.h>
+
+#define LOG_TAG "Quake"
+
+#include <GLES/gl.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#include <quakedef.h>
+
+// Timer utilities
+
+#define ENABLE_PMP
+#define USE_LOG
+
+#ifdef ENABLE_PMP
+
+static nsecs_t baseTime;
+static nsecs_t lastTime;
+static const unsigned int kStartTimeStackSize = 100;
+static nsecs_t startTimes[kStartTimeStackSize];
+static unsigned int startTimeStackPointer;
+
+static
+void PMP_Common(const char* fmt, va_list ap, char type)
+{
+	char buf[1024];
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+	
+	// Note: Timer acually has less than microsecond resolution, so track time in microseconds:
+	
+	nsecs_t time = systemTime(SYSTEM_TIME_THREAD) / 1000;
+	if(baseTime == 0)
+	{
+		baseTime = time;
+	}
+	time -= baseTime;
+	switch(type)
+	{
+	case '<':
+		{
+			if(startTimeStackPointer < kStartTimeStackSize)
+			{
+				startTimes[startTimeStackPointer] = time;
+			}
+#ifdef USE_LOG
+			LOGI("< %lld [%d] %s\n", time, startTimeStackPointer, buf);
+#else
+			fprintf(stderr, "Quake < %lld %d %s\n", time, startTimeStackPointer, buf);
+#endif
+			startTimeStackPointer++;
+		}
+		break;
+	case '>':
+		{
+			nsecs_t elapsed = 0;
+			if(startTimeStackPointer > 0)
+			{
+				--startTimeStackPointer;
+				if(startTimeStackPointer < kStartTimeStackSize)
+				{
+					elapsed = time - startTimes[startTimeStackPointer];
+				}
+			}
+#ifdef USE_LOG
+			LOGI("> %lld [%d] %lld %s\n", time, startTimeStackPointer, elapsed, buf);
+#else
+			fprintf(stderr, "Quake > %lld [%d] %lld %s\n", time, startTimeStackPointer, elapsed, buf);
+#endif
+		}
+		break;
+	default:
+#ifdef USE_LOG
+		LOGI("= %lld %lld %s\n", time, time - lastTime, buf);
+#else
+		fprintf(stderr, "Quake = %lld %s\n", time, buf);
+#endif
+		break;
+	}
+	lastTime = time;
+}
+
+void PMP_Begin(const char* fmt,...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	PMP_Common(fmt, ap, '<');
+}
+
+void PMP_Event(const char* fmt,...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	PMP_Common(fmt, ap, '=');
+}
+
+void PMP_End(const char* fmt,...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	PMP_Common(fmt, ap, '>');
+}
+
+#endif // ENABLE_PMP
diff --git a/quake/src/WinQuake/makezip.bat b/quake/src/WinQuake/makezip.bat
old mode 100755
new mode 100644
diff --git a/quake/src/WinQuake/masterMain.cpp b/quake/src/WinQuake/masterMain.cpp
new file mode 100644
index 0000000..893c1fa
--- /dev/null
+++ b/quake/src/WinQuake/masterMain.cpp
@@ -0,0 +1,156 @@
+/* //device/apps/Quake/quake/src/QW/client/main.c
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <nativehelper/jni.h>
+#include <stdio.h>
+#include <assert.h>
+#include <dlfcn.h>
+
+#define LOG_TAG "QuakeMaster"
+#include <utils/Log.h>
+
+int AndroidInit();
+int AndroidEvent2(int type, int value);
+int AndroidMotionEvent(unsigned long long eventTime, int action,
+        float x, float y, float pressure, float size, int deviceId);
+int AndroidTrackballEvent(unsigned long long eventTime, int action,
+        float x, float y);
+int AndroidStep(int width, int height);
+void AndroidQuit();
+
+jboolean
+qinit(JNIEnv *env, jobject thiz) {
+    LOGI("qinit");
+    return AndroidInit() ? JNI_TRUE : JNI_FALSE;
+ }
+
+jboolean
+qevent(JNIEnv *env, jobject thiz, jint type, jint value) {
+    return AndroidEvent2(type, value) ? JNI_TRUE : JNI_FALSE;
+}
+
+jboolean
+qmotionevent(JNIEnv *env, jobject thiz, jlong eventTime, jint action,
+        jfloat x, jfloat y, jfloat pressure, jfloat size, jint deviceId) {
+    return AndroidMotionEvent((unsigned long long) eventTime,
+            action, x, y, pressure, size,
+            deviceId) ? JNI_TRUE : JNI_FALSE;
+}
+
+jboolean
+qtrackballevent(JNIEnv *env, jobject thiz, jlong eventTime, jint action,
+        jfloat x, jfloat y) {
+    return AndroidTrackballEvent((unsigned long long) eventTime,
+            action, x, y) ? JNI_TRUE : JNI_FALSE;
+}
+
+jboolean
+qstep(JNIEnv *env, jobject thiz, jint width, jint height) {
+    return AndroidStep(width, height)  ? JNI_TRUE : JNI_FALSE;
+}
+
+void
+qquit(JNIEnv *env, jobject thiz) {
+    LOGI("qquit");
+    AndroidQuit();
+ }
+
+static const char *classPathName = "com/android/quake/QuakeLib";
+
+static JNINativeMethod methods[] = {
+  {"init", "()Z", (void*)qinit },
+  {"event", "(II)Z", (void*)qevent },
+  {"motionEvent", "(JIFFFFI)Z", (void*) qmotionevent },
+  {"trackballEvent", "(JIFF)Z", (void*) qtrackballevent },
+  {"step", "(II)Z", (void*)qstep },
+  {"quit", "()V", (void*)qquit },
+};
+
+/*
+ * Register several native methods for one class.
+ */
+static int registerNativeMethods(JNIEnv* env, const char* className,
+    JNINativeMethod* gMethods, int numMethods)
+{
+    jclass clazz;
+
+    clazz = env->FindClass(className);
+    if (clazz == NULL) {
+        fprintf(stderr,
+            "Native registration unable to find class '%s'\n", className);
+        return JNI_FALSE;
+    }
+    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
+        fprintf(stderr, "RegisterNatives failed for '%s'\n", className);
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+/*
+ * Register native methods for all classes we know about.
+ */
+static int registerNatives(JNIEnv* env)
+{
+  if (!registerNativeMethods(env, classPathName,
+                 methods, sizeof(methods) / sizeof(methods[0]))) {
+    return JNI_FALSE;
+  }
+
+  return JNI_TRUE;
+}
+
+/*
+ * Set some test stuff up.
+ *
+ * Returns the JNI version on success, -1 on failure.
+ */
+
+typedef union {
+    JNIEnv* env;
+    void* venv;
+} UnionJNIEnvToVoid;
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+    UnionJNIEnvToVoid uenv;
+    uenv.venv = NULL;
+    jint result = -1;
+    JNIEnv* env = NULL;
+
+    if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
+        fprintf(stderr, "ERROR: GetEnv failed\n");
+        goto bail;
+    }
+    env = uenv.env;
+
+    assert(env != NULL);
+
+    printf("In mgmain JNI_OnLoad\n");
+
+    if (!registerNatives(env)) {
+        fprintf(stderr, "ERROR: quakemaster native registration failed\n");
+        goto bail;
+    }
+
+    /* success -- return valid version number */
+    result = JNI_VERSION_1_4;
+
+bail:
+    return result;
+}
diff --git a/quake/src/WinQuake/mathlib.c b/quake/src/WinQuake/mathlib.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/mathlib.c
rename to quake/src/WinQuake/mathlib.cpp
diff --git a/quake/src/WinQuake/mathlib.h b/quake/src/WinQuake/mathlib.h
index ed0cbe8..9d96958 100644
--- a/quake/src/WinQuake/mathlib.h
+++ b/quake/src/WinQuake/mathlib.h
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // mathlib.h
 
 typedef float vec_t;
@@ -36,7 +36,7 @@
 extern vec3_t vec3_origin;
 extern	int nanmask;
 
-#define	IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
+#define	IS_NAN(x) isnanf(x) // (((*(int *)&x)&nanmask)==nanmask)
 
 #define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
 #define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
diff --git a/quake/src/WinQuake/menu.c b/quake/src/WinQuake/menu.c
deleted file mode 100644
index b50b98a..0000000
--- a/quake/src/WinQuake/menu.c
+++ /dev/null
@@ -1,3231 +0,0 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-#include "quakedef.h"
-
-#ifdef _WIN32
-#include "winquake.h"
-#endif
-
-void (*vid_menudrawfn)(void);
-void (*vid_menukeyfn)(int key);
-
-enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state;
-
-void M_Menu_Main_f (void);
-	void M_Menu_SinglePlayer_f (void);
-		void M_Menu_Load_f (void);
-		void M_Menu_Save_f (void);
-	void M_Menu_MultiPlayer_f (void);
-		void M_Menu_Setup_f (void);
-		void M_Menu_Net_f (void);
-	void M_Menu_Options_f (void);
-		void M_Menu_Keys_f (void);
-		void M_Menu_Video_f (void);
-	void M_Menu_Help_f (void);
-	void M_Menu_Quit_f (void);
-void M_Menu_SerialConfig_f (void);
-	void M_Menu_ModemConfig_f (void);
-void M_Menu_LanConfig_f (void);
-void M_Menu_GameOptions_f (void);
-void M_Menu_Search_f (void);
-void M_Menu_ServerList_f (void);
-
-void M_Main_Draw (void);
-	void M_SinglePlayer_Draw (void);
-		void M_Load_Draw (void);
-		void M_Save_Draw (void);
-	void M_MultiPlayer_Draw (void);
-		void M_Setup_Draw (void);
-		void M_Net_Draw (void);
-	void M_Options_Draw (void);
-		void M_Keys_Draw (void);
-		void M_Video_Draw (void);
-	void M_Help_Draw (void);
-	void M_Quit_Draw (void);
-void M_SerialConfig_Draw (void);
-	void M_ModemConfig_Draw (void);
-void M_LanConfig_Draw (void);
-void M_GameOptions_Draw (void);
-void M_Search_Draw (void);
-void M_ServerList_Draw (void);
-
-void M_Main_Key (int key);
-	void M_SinglePlayer_Key (int key);
-		void M_Load_Key (int key);
-		void M_Save_Key (int key);
-	void M_MultiPlayer_Key (int key);
-		void M_Setup_Key (int key);
-		void M_Net_Key (int key);
-	void M_Options_Key (int key);
-		void M_Keys_Key (int key);
-		void M_Video_Key (int key);
-	void M_Help_Key (int key);
-	void M_Quit_Key (int key);
-void M_SerialConfig_Key (int key);
-	void M_ModemConfig_Key (int key);
-void M_LanConfig_Key (int key);
-void M_GameOptions_Key (int key);
-void M_Search_Key (int key);
-void M_ServerList_Key (int key);
-
-qboolean	m_entersound;		// play after drawing a frame, so caching
-								// won't disrupt the sound
-qboolean	m_recursiveDraw;
-
-int			m_return_state;
-qboolean	m_return_onerror;
-char		m_return_reason [32];
-
-#define StartingGame	(m_multiplayer_cursor == 1)
-#define JoiningGame		(m_multiplayer_cursor == 0)
-#define SerialConfig	(m_net_cursor == 0)
-#define DirectConfig	(m_net_cursor == 1)
-#define	IPXConfig		(m_net_cursor == 2)
-#define	TCPIPConfig		(m_net_cursor == 3)
-
-void M_ConfigureNetSubsystem(void);
-
-/*
-================
-M_DrawCharacter
-
-Draws one solid graphics character
-================
-*/
-void M_DrawCharacter (int cx, int line, int num)
-{
-	Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
-}
-
-void M_Print (int cx, int cy, char *str)
-{
-	while (*str)
-	{
-		M_DrawCharacter (cx, cy, (*str)+128);
-		str++;
-		cx += 8;
-	}
-}
-
-void M_PrintWhite (int cx, int cy, char *str)
-{
-	while (*str)
-	{
-		M_DrawCharacter (cx, cy, *str);
-		str++;
-		cx += 8;
-	}
-}
-
-void M_DrawTransPic (int x, int y, qpic_t *pic)
-{
-	Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
-}
-
-void M_DrawPic (int x, int y, qpic_t *pic)
-{
-	Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
-}
-
-byte identityTable[256];
-byte translationTable[256];
-
-void M_BuildTranslationTable(int top, int bottom)
-{
-	int		j;
-	byte	*dest, *source;
-
-	for (j = 0; j < 256; j++)
-		identityTable[j] = j;
-	dest = translationTable;
-	source = identityTable;
-	memcpy (dest, source, 256);
-
-	if (top < 128)	// the artists made some backwards ranges.  sigh.
-		memcpy (dest + TOP_RANGE, source + top, 16);
-	else
-		for (j=0 ; j<16 ; j++)
-			dest[TOP_RANGE+j] = source[top+15-j];
-
-	if (bottom < 128)
-		memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
-	else
-		for (j=0 ; j<16 ; j++)
-			dest[BOTTOM_RANGE+j] = source[bottom+15-j];
-}
-
-
-void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
-{
-	Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
-}
-
-
-void M_DrawTextBox (int x, int y, int width, int lines)
-{
-	qpic_t	*p;
-	int		cx, cy;
-	int		n;
-
-	// draw left side
-	cx = x;
-	cy = y;
-	p = Draw_CachePic ("gfx/box_tl.lmp");
-	M_DrawTransPic (cx, cy, p);
-	p = Draw_CachePic ("gfx/box_ml.lmp");
-	for (n = 0; n < lines; n++)
-	{
-		cy += 8;
-		M_DrawTransPic (cx, cy, p);
-	}
-	p = Draw_CachePic ("gfx/box_bl.lmp");
-	M_DrawTransPic (cx, cy+8, p);
-
-	// draw middle
-	cx += 8;
-	while (width > 0)
-	{
-		cy = y;
-		p = Draw_CachePic ("gfx/box_tm.lmp");
-		M_DrawTransPic (cx, cy, p);
-		p = Draw_CachePic ("gfx/box_mm.lmp");
-		for (n = 0; n < lines; n++)
-		{
-			cy += 8;
-			if (n == 1)
-				p = Draw_CachePic ("gfx/box_mm2.lmp");
-			M_DrawTransPic (cx, cy, p);
-		}
-		p = Draw_CachePic ("gfx/box_bm.lmp");
-		M_DrawTransPic (cx, cy+8, p);
-		width -= 2;
-		cx += 16;
-	}
-
-	// draw right side
-	cy = y;
-	p = Draw_CachePic ("gfx/box_tr.lmp");
-	M_DrawTransPic (cx, cy, p);
-	p = Draw_CachePic ("gfx/box_mr.lmp");
-	for (n = 0; n < lines; n++)
-	{
-		cy += 8;
-		M_DrawTransPic (cx, cy, p);
-	}
-	p = Draw_CachePic ("gfx/box_br.lmp");
-	M_DrawTransPic (cx, cy+8, p);
-}
-
-//=============================================================================
-
-int m_save_demonum;
-
-/*
-================
-M_ToggleMenu_f
-================
-*/
-void M_ToggleMenu_f (void)
-{
-	m_entersound = true;
-
-	if (key_dest == key_menu)
-	{
-		if (m_state != m_main)
-		{
-			M_Menu_Main_f ();
-			return;
-		}
-		key_dest = key_game;
-		m_state = m_none;
-		return;
-	}
-	if (key_dest == key_console)
-	{
-		Con_ToggleConsole_f ();
-	}
-	else
-	{
-		M_Menu_Main_f ();
-	}
-}
-
-
-//=============================================================================
-/* MAIN MENU */
-
-int	m_main_cursor;
-#define	MAIN_ITEMS	5
-
-
-void M_Menu_Main_f (void)
-{
-	if (key_dest != key_menu)
-	{
-		m_save_demonum = cls.demonum;
-		cls.demonum = -1;
-	}
-	key_dest = key_menu;
-	m_state = m_main;
-	m_entersound = true;
-}
-
-
-void M_Main_Draw (void)
-{
-	int		f;
-	qpic_t	*p;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/ttl_main.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-	M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") );
-
-	f = (int)(host_time * 10)%6;
-
-	M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
-}
-
-
-void M_Main_Key (int key)
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-		key_dest = key_game;
-		m_state = m_none;
-		cls.demonum = m_save_demonum;
-		if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected)
-			CL_NextDemo ();
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (++m_main_cursor >= MAIN_ITEMS)
-			m_main_cursor = 0;
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (--m_main_cursor < 0)
-			m_main_cursor = MAIN_ITEMS - 1;
-		break;
-
-	case K_ENTER:
-		m_entersound = true;
-
-		switch (m_main_cursor)
-		{
-		case 0:
-			M_Menu_SinglePlayer_f ();
-			break;
-
-		case 1:
-			M_Menu_MultiPlayer_f ();
-			break;
-
-		case 2:
-			M_Menu_Options_f ();
-			break;
-
-		case 3:
-			M_Menu_Help_f ();
-			break;
-
-		case 4:
-			M_Menu_Quit_f ();
-			break;
-		}
-	}
-}
-
-//=============================================================================
-/* SINGLE PLAYER MENU */
-
-int	m_singleplayer_cursor;
-#define	SINGLEPLAYER_ITEMS	3
-
-
-void M_Menu_SinglePlayer_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_singleplayer;
-	m_entersound = true;
-}
-
-
-void M_SinglePlayer_Draw (void)
-{
-	int		f;
-	qpic_t	*p;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/ttl_sgl.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-	M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") );
-
-	f = (int)(host_time * 10)%6;
-
-	M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
-}
-
-
-void M_SinglePlayer_Key (int key)
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_Main_f ();
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
-			m_singleplayer_cursor = 0;
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (--m_singleplayer_cursor < 0)
-			m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;
-		break;
-
-	case K_ENTER:
-		m_entersound = true;
-
-		switch (m_singleplayer_cursor)
-		{
-		case 0:
-			if (sv.active)
-				if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n"))
-					break;
-			key_dest = key_game;
-			if (sv.active)
-				Cbuf_AddText ("disconnect\n");
-			Cbuf_AddText ("maxplayers 1\n");
-			Cbuf_AddText ("map start\n");
-			break;
-
-		case 1:
-			M_Menu_Load_f ();
-			break;
-
-		case 2:
-			M_Menu_Save_f ();
-			break;
-		}
-	}
-}
-
-//=============================================================================
-/* LOAD/SAVE MENU */
-
-int		load_cursor;		// 0 < load_cursor < MAX_SAVEGAMES
-
-#define	MAX_SAVEGAMES		12
-char	m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
-int		loadable[MAX_SAVEGAMES];
-
-void M_ScanSaves (void)
-{
-	int		i, j;
-	char	name[MAX_OSPATH];
-	FILE	*f;
-	int		version;
-
-	for (i=0 ; i<MAX_SAVEGAMES ; i++)
-	{
-		strcpy (m_filenames[i], "--- UNUSED SLOT ---");
-		loadable[i] = false;
-		sprintf (name, "%s/s%i.sav", com_gamedir, i);
-		f = fopen (name, "r");
-		if (!f)
-			continue;
-		fscanf (f, "%i\n", &version);
-		fscanf (f, "%79s\n", name);
-		strncpy (m_filenames[i], name, sizeof(m_filenames[i])-1);
-
-	// change _ back to space
-		for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
-			if (m_filenames[i][j] == '_')
-				m_filenames[i][j] = ' ';
-		loadable[i] = true;
-		fclose (f);
-	}
-}
-
-void M_Menu_Load_f (void)
-{
-	m_entersound = true;
-	m_state = m_load;
-	key_dest = key_menu;
-	M_ScanSaves ();
-}
-
-
-void M_Menu_Save_f (void)
-{
-	if (!sv.active)
-		return;
-	if (cl.intermission)
-		return;
-	if (svs.maxclients != 1)
-		return;
-	m_entersound = true;
-	m_state = m_save;
-	key_dest = key_menu;
-	M_ScanSaves ();
-}
-
-
-void M_Load_Draw (void)
-{
-	int		i;
-	qpic_t	*p;
-
-	p = Draw_CachePic ("gfx/p_load.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-
-	for (i=0 ; i< MAX_SAVEGAMES; i++)
-		M_Print (16, 32 + 8*i, m_filenames[i]);
-
-// line cursor
-	M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
-}
-
-
-void M_Save_Draw (void)
-{
-	int		i;
-	qpic_t	*p;
-
-	p = Draw_CachePic ("gfx/p_save.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-
-	for (i=0 ; i<MAX_SAVEGAMES ; i++)
-		M_Print (16, 32 + 8*i, m_filenames[i]);
-
-// line cursor
-	M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
-}
-
-
-void M_Load_Key (int k)
-{
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_SinglePlayer_f ();
-		break;
-
-	case K_ENTER:
-		S_LocalSound ("misc/menu2.wav");
-		if (!loadable[load_cursor])
-			return;
-		m_state = m_none;
-		key_dest = key_game;
-
-	// Host_Loadgame_f can't bring up the loading plaque because too much
-	// stack space has been used, so do it now
-		SCR_BeginLoadingPlaque ();
-
-	// issue the load command
-		Cbuf_AddText (va ("load s%i\n", load_cursor) );
-		return;
-
-	case K_UPARROW:
-	case K_LEFTARROW:
-		S_LocalSound ("misc/menu1.wav");
-		load_cursor--;
-		if (load_cursor < 0)
-			load_cursor = MAX_SAVEGAMES-1;
-		break;
-
-	case K_DOWNARROW:
-	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
-		load_cursor++;
-		if (load_cursor >= MAX_SAVEGAMES)
-			load_cursor = 0;
-		break;
-	}
-}
-
-
-void M_Save_Key (int k)
-{
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_SinglePlayer_f ();
-		break;
-
-	case K_ENTER:
-		m_state = m_none;
-		key_dest = key_game;
-		Cbuf_AddText (va("save s%i\n", load_cursor));
-		return;
-
-	case K_UPARROW:
-	case K_LEFTARROW:
-		S_LocalSound ("misc/menu1.wav");
-		load_cursor--;
-		if (load_cursor < 0)
-			load_cursor = MAX_SAVEGAMES-1;
-		break;
-
-	case K_DOWNARROW:
-	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
-		load_cursor++;
-		if (load_cursor >= MAX_SAVEGAMES)
-			load_cursor = 0;
-		break;
-	}
-}
-
-//=============================================================================
-/* MULTIPLAYER MENU */
-
-int	m_multiplayer_cursor;
-#define	MULTIPLAYER_ITEMS	3
-
-
-void M_Menu_MultiPlayer_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_multiplayer;
-	m_entersound = true;
-}
-
-
-void M_MultiPlayer_Draw (void)
-{
-	int		f;
-	qpic_t	*p;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-	M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") );
-
-	f = (int)(host_time * 10)%6;
-
-	M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
-
-	if (serialAvailable || ipxAvailable || tcpipAvailable)
-		return;
-	M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
-}
-
-
-void M_MultiPlayer_Key (int key)
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_Main_f ();
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
-			m_multiplayer_cursor = 0;
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (--m_multiplayer_cursor < 0)
-			m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;
-		break;
-
-	case K_ENTER:
-		m_entersound = true;
-		switch (m_multiplayer_cursor)
-		{
-		case 0:
-			if (serialAvailable || ipxAvailable || tcpipAvailable)
-				M_Menu_Net_f ();
-			break;
-
-		case 1:
-			if (serialAvailable || ipxAvailable || tcpipAvailable)
-				M_Menu_Net_f ();
-			break;
-
-		case 2:
-			M_Menu_Setup_f ();
-			break;
-		}
-	}
-}
-
-//=============================================================================
-/* SETUP MENU */
-
-int		setup_cursor = 4;
-int		setup_cursor_table[] = {40, 56, 80, 104, 140};
-
-char	setup_hostname[16];
-char	setup_myname[16];
-int		setup_oldtop;
-int		setup_oldbottom;
-int		setup_top;
-int		setup_bottom;
-
-#define	NUM_SETUP_CMDS	5
-
-void M_Menu_Setup_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_setup;
-	m_entersound = true;
-	Q_strcpy(setup_myname, cl_name.string);
-	Q_strcpy(setup_hostname, hostname.string);
-	setup_top = setup_oldtop = ((int)cl_color.value) >> 4;
-	setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;
-}
-
-
-void M_Setup_Draw (void)
-{
-	qpic_t	*p;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-
-	M_Print (64, 40, "Hostname");
-	M_DrawTextBox (160, 32, 16, 1);
-	M_Print (168, 40, setup_hostname);
-
-	M_Print (64, 56, "Your name");
-	M_DrawTextBox (160, 48, 16, 1);
-	M_Print (168, 56, setup_myname);
-
-	M_Print (64, 80, "Shirt color");
-	M_Print (64, 104, "Pants color");
-
-	M_DrawTextBox (64, 140-8, 14, 1);
-	M_Print (72, 140, "Accept Changes");
-
-	p = Draw_CachePic ("gfx/bigbox.lmp");
-	M_DrawTransPic (160, 64, p);
-	p = Draw_CachePic ("gfx/menuplyr.lmp");
-	M_BuildTranslationTable(setup_top*16, setup_bottom*16);
-	M_DrawTransPicTranslate (172, 72, p);
-
-	M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));
-
-	if (setup_cursor == 0)
-		M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
-
-	if (setup_cursor == 1)
-		M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
-}
-
-
-void M_Setup_Key (int k)
-{
-	int			l;
-
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_MultiPlayer_f ();
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		setup_cursor--;
-		if (setup_cursor < 0)
-			setup_cursor = NUM_SETUP_CMDS-1;
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		setup_cursor++;
-		if (setup_cursor >= NUM_SETUP_CMDS)
-			setup_cursor = 0;
-		break;
-
-	case K_LEFTARROW:
-		if (setup_cursor < 2)
-			return;
-		S_LocalSound ("misc/menu3.wav");
-		if (setup_cursor == 2)
-			setup_top = setup_top - 1;
-		if (setup_cursor == 3)
-			setup_bottom = setup_bottom - 1;
-		break;
-	case K_RIGHTARROW:
-		if (setup_cursor < 2)
-			return;
-forward:
-		S_LocalSound ("misc/menu3.wav");
-		if (setup_cursor == 2)
-			setup_top = setup_top + 1;
-		if (setup_cursor == 3)
-			setup_bottom = setup_bottom + 1;
-		break;
-
-	case K_ENTER:
-		if (setup_cursor == 0 || setup_cursor == 1)
-			return;
-
-		if (setup_cursor == 2 || setup_cursor == 3)
-			goto forward;
-
-		// setup_cursor == 4 (OK)
-		if (Q_strcmp(cl_name.string, setup_myname) != 0)
-			Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
-		if (Q_strcmp(hostname.string, setup_hostname) != 0)
-			Cvar_Set("hostname", setup_hostname);
-		if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
-			Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) );
-		m_entersound = true;
-		M_Menu_MultiPlayer_f ();
-		break;
-
-	case K_BACKSPACE:
-		if (setup_cursor == 0)
-		{
-			if (strlen(setup_hostname))
-				setup_hostname[strlen(setup_hostname)-1] = 0;
-		}
-
-		if (setup_cursor == 1)
-		{
-			if (strlen(setup_myname))
-				setup_myname[strlen(setup_myname)-1] = 0;
-		}
-		break;
-
-	default:
-		if (k < 32 || k > 127)
-			break;
-		if (setup_cursor == 0)
-		{
-			l = strlen(setup_hostname);
-			if (l < 15)
-			{
-				setup_hostname[l+1] = 0;
-				setup_hostname[l] = k;
-			}
-		}
-		if (setup_cursor == 1)
-		{
-			l = strlen(setup_myname);
-			if (l < 15)
-			{
-				setup_myname[l+1] = 0;
-				setup_myname[l] = k;
-			}
-		}
-	}
-
-	if (setup_top > 13)
-		setup_top = 0;
-	if (setup_top < 0)
-		setup_top = 13;
-	if (setup_bottom > 13)
-		setup_bottom = 0;
-	if (setup_bottom < 0)
-		setup_bottom = 13;
-}
-
-//=============================================================================
-/* NET MENU */
-
-int	m_net_cursor;
-int m_net_items;
-int m_net_saveHeight;
-
-char *net_helpMessage [] =
-{
-/* .........1.........2.... */
-  "                        ",
-  " Two computers connected",
-  "   through two modems.  ",
-  "                        ",
-
-  "                        ",
-  " Two computers connected",
-  " by a null-modem cable. ",
-  "                        ",
-
-  " Novell network LANs    ",
-  " or Windows 95 DOS-box. ",
-  "                        ",
-  "(LAN=Local Area Network)",
-
-  " Commonly used to play  ",
-  " over the Internet, but ",
-  " also used on a Local   ",
-  " Area Network.          "
-};
-
-void M_Menu_Net_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_net;
-	m_entersound = true;
-	m_net_items = 4;
-
-	if (m_net_cursor >= m_net_items)
-		m_net_cursor = 0;
-	m_net_cursor--;
-	M_Net_Key (K_DOWNARROW);
-}
-
-
-void M_Net_Draw (void)
-{
-	int		f;
-	qpic_t	*p;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-
-	f = 32;
-
-	if (serialAvailable)
-	{
-		p = Draw_CachePic ("gfx/netmen1.lmp");
-	}
-	else
-	{
-#ifdef _WIN32
-		p = NULL;
-#else
-		p = Draw_CachePic ("gfx/dim_modm.lmp");
-#endif
-	}
-
-	if (p)
-		M_DrawTransPic (72, f, p);
-
-	f += 19;
-
-	if (serialAvailable)
-	{
-		p = Draw_CachePic ("gfx/netmen2.lmp");
-	}
-	else
-	{
-#ifdef _WIN32
-		p = NULL;
-#else
-		p = Draw_CachePic ("gfx/dim_drct.lmp");
-#endif
-	}
-
-	if (p)
-		M_DrawTransPic (72, f, p);
-
-	f += 19;
-	if (ipxAvailable)
-		p = Draw_CachePic ("gfx/netmen3.lmp");
-	else
-		p = Draw_CachePic ("gfx/dim_ipx.lmp");
-	M_DrawTransPic (72, f, p);
-
-	f += 19;
-	if (tcpipAvailable)
-		p = Draw_CachePic ("gfx/netmen4.lmp");
-	else
-		p = Draw_CachePic ("gfx/dim_tcp.lmp");
-	M_DrawTransPic (72, f, p);
-
-	if (m_net_items == 5)	// JDC, could just be removed
-	{
-		f += 19;
-		p = Draw_CachePic ("gfx/netmen5.lmp");
-		M_DrawTransPic (72, f, p);
-	}
-
-	f = (320-26*8)/2;
-	M_DrawTextBox (f, 134, 24, 4);
-	f += 8;
-	M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]);
-	M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]);
-	M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]);
-	M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]);
-
-	f = (int)(host_time * 10)%6;
-	M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
-}
-
-
-void M_Net_Key (int k)
-{
-again:
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_MultiPlayer_f ();
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (++m_net_cursor >= m_net_items)
-			m_net_cursor = 0;
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		if (--m_net_cursor < 0)
-			m_net_cursor = m_net_items - 1;
-		break;
-
-	case K_ENTER:
-		m_entersound = true;
-
-		switch (m_net_cursor)
-		{
-		case 0:
-			M_Menu_SerialConfig_f ();
-			break;
-
-		case 1:
-			M_Menu_SerialConfig_f ();
-			break;
-
-		case 2:
-			M_Menu_LanConfig_f ();
-			break;
-
-		case 3:
-			M_Menu_LanConfig_f ();
-			break;
-
-		case 4:
-// multiprotocol
-			break;
-		}
-	}
-
-	if (m_net_cursor == 0 && !serialAvailable)
-		goto again;
-	if (m_net_cursor == 1 && !serialAvailable)
-		goto again;
-	if (m_net_cursor == 2 && !ipxAvailable)
-		goto again;
-	if (m_net_cursor == 3 && !tcpipAvailable)
-		goto again;
-}
-
-//=============================================================================
-/* OPTIONS MENU */
-
-#ifdef _WIN32
-#define	OPTIONS_ITEMS	14
-#else
-#define	OPTIONS_ITEMS	13
-#endif
-
-#define	SLIDER_RANGE	10
-
-int		options_cursor;
-
-void M_Menu_Options_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_options;
-	m_entersound = true;

-
-#ifdef _WIN32

-	if ((options_cursor == 13) && (modestate != MS_WINDOWED))

-	{

-		options_cursor = 0;

-	}

-#endif

-}
-
-
-void M_AdjustSliders (int dir)
-{
-	S_LocalSound ("misc/menu3.wav");
-
-	switch (options_cursor)
-	{
-	case 3:	// screen size
-		scr_viewsize.value += dir * 10;
-		if (scr_viewsize.value < 30)
-			scr_viewsize.value = 30;
-		if (scr_viewsize.value > 120)
-			scr_viewsize.value = 120;
-		Cvar_SetValue ("viewsize", scr_viewsize.value);
-		break;
-	case 4:	// gamma
-		v_gamma.value -= dir * 0.05;
-		if (v_gamma.value < 0.5)
-			v_gamma.value = 0.5;
-		if (v_gamma.value > 1)
-			v_gamma.value = 1;
-		Cvar_SetValue ("gamma", v_gamma.value);
-		break;
-	case 5:	// mouse speed
-		sensitivity.value += dir * 0.5;
-		if (sensitivity.value < 1)
-			sensitivity.value = 1;
-		if (sensitivity.value > 11)
-			sensitivity.value = 11;
-		Cvar_SetValue ("sensitivity", sensitivity.value);
-		break;
-	case 6:	// music volume
-#ifdef _WIN32
-		bgmvolume.value += dir * 1.0;
-#else
-		bgmvolume.value += dir * 0.1;
-#endif
-		if (bgmvolume.value < 0)
-			bgmvolume.value = 0;
-		if (bgmvolume.value > 1)
-			bgmvolume.value = 1;
-		Cvar_SetValue ("bgmvolume", bgmvolume.value);
-		break;
-	case 7:	// sfx volume
-		volume.value += dir * 0.1;
-		if (volume.value < 0)
-			volume.value = 0;
-		if (volume.value > 1)
-			volume.value = 1;
-		Cvar_SetValue ("volume", volume.value);
-		break;
-
-	case 8:	// allways run
-		if (cl_forwardspeed.value > 200)
-		{
-			Cvar_SetValue ("cl_forwardspeed", 200);
-			Cvar_SetValue ("cl_backspeed", 200);
-		}
-		else
-		{
-			Cvar_SetValue ("cl_forwardspeed", 400);
-			Cvar_SetValue ("cl_backspeed", 400);
-		}
-		break;
-
-	case 9:	// invert mouse
-		Cvar_SetValue ("m_pitch", -m_pitch.value);
-		break;
-
-	case 10:	// lookspring
-		Cvar_SetValue ("lookspring", !lookspring.value);
-		break;
-
-	case 11:	// lookstrafe
-		Cvar_SetValue ("lookstrafe", !lookstrafe.value);
-		break;
-
-#ifdef _WIN32
-	case 13:	// _windowed_mouse
-		Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value);
-		break;
-#endif
-	}
-}
-
-
-void M_DrawSlider (int x, int y, float range)
-{
-	int	i;
-
-	if (range < 0)
-		range = 0;
-	if (range > 1)
-		range = 1;
-	M_DrawCharacter (x-8, y, 128);
-	for (i=0 ; i<SLIDER_RANGE ; i++)
-		M_DrawCharacter (x + i*8, y, 129);
-	M_DrawCharacter (x+i*8, y, 130);
-	M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);
-}
-
-void M_DrawCheckbox (int x, int y, int on)
-{
-#if 0
-	if (on)
-		M_DrawCharacter (x, y, 131);
-	else
-		M_DrawCharacter (x, y, 129);
-#endif
-	if (on)
-		M_Print (x, y, "on");
-	else
-		M_Print (x, y, "off");
-}
-
-void M_Options_Draw (void)
-{
-	float		r;
-	qpic_t	*p;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_option.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-
-	M_Print (16, 32, "    Customize controls");
-	M_Print (16, 40, "         Go to console");
-	M_Print (16, 48, "     Reset to defaults");
-
-	M_Print (16, 56, "           Screen size");
-	r = (scr_viewsize.value - 30) / (120 - 30);
-	M_DrawSlider (220, 56, r);
-
-	M_Print (16, 64, "            Brightness");
-	r = (1.0 - v_gamma.value) / 0.5;
-	M_DrawSlider (220, 64, r);
-
-	M_Print (16, 72, "           Mouse Speed");
-	r = (sensitivity.value - 1)/10;
-	M_DrawSlider (220, 72, r);
-
-	M_Print (16, 80, "       CD Music Volume");
-	r = bgmvolume.value;
-	M_DrawSlider (220, 80, r);
-
-	M_Print (16, 88, "          Sound Volume");
-	r = volume.value;
-	M_DrawSlider (220, 88, r);
-
-	M_Print (16, 96,  "            Always Run");
-	M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200);
-
-	M_Print (16, 104, "          Invert Mouse");
-	M_DrawCheckbox (220, 104, m_pitch.value < 0);
-
-	M_Print (16, 112, "            Lookspring");
-	M_DrawCheckbox (220, 112, lookspring.value);
-
-	M_Print (16, 120, "            Lookstrafe");
-	M_DrawCheckbox (220, 120, lookstrafe.value);
-
-	if (vid_menudrawfn)
-		M_Print (16, 128, "         Video Options");
-
-#ifdef _WIN32
-	if (modestate == MS_WINDOWED)
-	{
-		M_Print (16, 136, "             Use Mouse");
-		M_DrawCheckbox (220, 136, _windowed_mouse.value);
-	}
-#endif
-
-// cursor
-	M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));
-}
-
-
-void M_Options_Key (int k)
-{
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_Main_f ();
-		break;
-
-	case K_ENTER:
-		m_entersound = true;
-		switch (options_cursor)
-		{
-		case 0:
-			M_Menu_Keys_f ();
-			break;
-		case 1:
-			m_state = m_none;
-			Con_ToggleConsole_f ();
-			break;
-		case 2:
-			Cbuf_AddText ("exec default.cfg\n");
-			break;
-		case 12:
-			M_Menu_Video_f ();
-			break;
-		default:
-			M_AdjustSliders (1);
-			break;
-		}
-		return;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		options_cursor--;
-		if (options_cursor < 0)
-			options_cursor = OPTIONS_ITEMS-1;
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		options_cursor++;
-		if (options_cursor >= OPTIONS_ITEMS)
-			options_cursor = 0;
-		break;
-
-	case K_LEFTARROW:
-		M_AdjustSliders (-1);
-		break;
-
-	case K_RIGHTARROW:
-		M_AdjustSliders (1);
-		break;
-	}
-
-	if (options_cursor == 12 && vid_menudrawfn == NULL)
-	{
-		if (k == K_UPARROW)
-			options_cursor = 11;
-		else
-			options_cursor = 0;
-	}
-
-#ifdef _WIN32
-	if ((options_cursor == 13) && (modestate != MS_WINDOWED))
-	{
-		if (k == K_UPARROW)
-			options_cursor = 12;
-		else
-			options_cursor = 0;
-	}
-#endif
-}
-
-//=============================================================================
-/* KEYS MENU */
-
-char *bindnames[][2] =
-{
-{"+attack", 		"attack"},
-{"impulse 10", 		"change weapon"},
-{"+jump", 			"jump / swim up"},
-{"+forward", 		"walk forward"},
-{"+back", 			"backpedal"},
-{"+left", 			"turn left"},
-{"+right", 			"turn right"},
-{"+speed", 			"run"},
-{"+moveleft", 		"step left"},
-{"+moveright", 		"step right"},
-{"+strafe", 		"sidestep"},
-{"+lookup", 		"look up"},
-{"+lookdown", 		"look down"},
-{"centerview", 		"center view"},
-{"+mlook", 			"mouse look"},
-{"+klook", 			"keyboard look"},
-{"+moveup",			"swim up"},
-{"+movedown",		"swim down"}
-};
-
-#define	NUMCOMMANDS	(sizeof(bindnames)/sizeof(bindnames[0]))
-
-int		keys_cursor;
-int		bind_grab;
-
-void M_Menu_Keys_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_keys;
-	m_entersound = true;
-}
-
-
-void M_FindKeysForCommand (char *command, int *twokeys)
-{
-	int		count;
-	int		j;
-	int		l;
-	char	*b;
-
-	twokeys[0] = twokeys[1] = -1;
-	l = strlen(command);
-	count = 0;
-
-	for (j=0 ; j<256 ; j++)
-	{
-		b = keybindings[j];
-		if (!b)
-			continue;
-		if (!strncmp (b, command, l) )
-		{
-			twokeys[count] = j;
-			count++;
-			if (count == 2)
-				break;
-		}
-	}
-}
-
-void M_UnbindCommand (char *command)
-{
-	int		j;
-	int		l;
-	char	*b;
-
-	l = strlen(command);
-
-	for (j=0 ; j<256 ; j++)
-	{
-		b = keybindings[j];
-		if (!b)
-			continue;
-		if (!strncmp (b, command, l) )
-			Key_SetBinding (j, "");
-	}
-}
-
-
-void M_Keys_Draw (void)
-{
-	int		i, l;
-	int		keys[2];
-	char	*name;
-	int		x, y;
-	qpic_t	*p;
-
-	p = Draw_CachePic ("gfx/ttl_cstm.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-
-	if (bind_grab)
-		M_Print (12, 32, "Press a key or button for this action");
-	else
-		M_Print (18, 32, "Enter to change, backspace to clear");
-
-// search for known bindings
-	for (i=0 ; i<NUMCOMMANDS ; i++)
-	{
-		y = 48 + 8*i;
-
-		M_Print (16, y, bindnames[i][1]);
-
-		l = strlen (bindnames[i][0]);
-
-		M_FindKeysForCommand (bindnames[i][0], keys);
-
-		if (keys[0] == -1)
-		{
-			M_Print (140, y, "???");
-		}
-		else
-		{
-			name = Key_KeynumToString (keys[0]);
-			M_Print (140, y, name);
-			x = strlen(name) * 8;
-			if (keys[1] != -1)
-			{
-				M_Print (140 + x + 8, y, "or");
-				M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
-			}
-		}
-	}
-
-	if (bind_grab)
-		M_DrawCharacter (130, 48 + keys_cursor*8, '=');
-	else
-		M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
-}
-
-
-void M_Keys_Key (int k)
-{
-	char	cmd[80];
-	int		keys[2];
-
-	if (bind_grab)
-	{	// defining a key
-		S_LocalSound ("misc/menu1.wav");
-		if (k == K_ESCAPE)
-		{
-			bind_grab = false;
-		}
-		else if (k != '`')
-		{
-			sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
-			Cbuf_InsertText (cmd);
-		}
-
-		bind_grab = false;
-		return;
-	}
-
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_Options_f ();
-		break;
-
-	case K_LEFTARROW:
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		keys_cursor--;
-		if (keys_cursor < 0)
-			keys_cursor = NUMCOMMANDS-1;
-		break;
-
-	case K_DOWNARROW:
-	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
-		keys_cursor++;
-		if (keys_cursor >= NUMCOMMANDS)
-			keys_cursor = 0;
-		break;
-
-	case K_ENTER:		// go into bind mode
-		M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
-		S_LocalSound ("misc/menu2.wav");
-		if (keys[1] != -1)
-			M_UnbindCommand (bindnames[keys_cursor][0]);
-		bind_grab = true;
-		break;
-
-	case K_BACKSPACE:		// delete bindings
-	case K_DEL:				// delete bindings
-		S_LocalSound ("misc/menu2.wav");
-		M_UnbindCommand (bindnames[keys_cursor][0]);
-		break;
-	}
-}
-
-//=============================================================================
-/* VIDEO MENU */
-
-void M_Menu_Video_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_video;
-	m_entersound = true;
-}
-
-
-void M_Video_Draw (void)
-{
-	(*vid_menudrawfn) ();
-}
-
-
-void M_Video_Key (int key)
-{
-	(*vid_menukeyfn) (key);
-}
-
-//=============================================================================
-/* HELP MENU */
-
-int		help_page;
-#define	NUM_HELP_PAGES	6
-
-
-void M_Menu_Help_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_help;
-	m_entersound = true;
-	help_page = 0;
-}
-
-
-
-void M_Help_Draw (void)
-{
-	M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
-}
-
-
-void M_Help_Key (int key)
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_Main_f ();
-		break;
-
-	case K_UPARROW:
-	case K_RIGHTARROW:
-		m_entersound = true;
-		if (++help_page >= NUM_HELP_PAGES)
-			help_page = 0;
-		break;
-
-	case K_DOWNARROW:
-	case K_LEFTARROW:
-		m_entersound = true;
-		if (--help_page < 0)
-			help_page = NUM_HELP_PAGES-1;
-		break;
-	}
-
-}
-
-//=============================================================================
-/* QUIT MENU */
-
-int		msgNumber;
-int		m_quit_prevstate;
-qboolean	wasInMenus;
-
-#ifndef	_WIN32
-char *quitMessage [] = 
-{
-/* .........1.........2.... */
-  "  Are you gonna quit    ",
-  "  this game just like   ",
-  "   everything else?     ",
-  "                        ",
- 
-  " Milord, methinks that  ",
-  "   thou art a lowly     ",
-  " quitter. Is this true? ",
-  "                        ",
-
-  " Do I need to bust your ",
-  "  face open for trying  ",
-  "        to quit?        ",
-  "                        ",
-
-  " Man, I oughta smack you",
-  "   for trying to quit!  ",
-  "     Press Y to get     ",
-  "      smacked out.      ",
- 
-  " Press Y to quit like a ",
-  "   big loser in life.   ",
-  "  Press N to stay proud ",
-  "    and successful!     ",
- 
-  "   If you press Y to    ",
-  "  quit, I will summon   ",
-  "  Satan all over your   ",
-  "      hard drive!       ",
- 
-  "  Um, Asmodeus dislikes ",
-  " his children trying to ",
-  " quit. Press Y to return",
-  "   to your Tinkertoys.  ",
- 
-  "  If you quit now, I'll ",
-  "  throw a blanket-party ",
-  "   for you next time!   ",
-  "                        "
-};
-#endif
-
-void M_Menu_Quit_f (void)
-{
-	if (m_state == m_quit)
-		return;
-	wasInMenus = (key_dest == key_menu);
-	key_dest = key_menu;
-	m_quit_prevstate = m_state;
-	m_state = m_quit;
-	m_entersound = true;
-	msgNumber = rand()&7;
-}
-
-
-void M_Quit_Key (int key)
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-	case 'n':
-	case 'N':
-		if (wasInMenus)
-		{
-			m_state = m_quit_prevstate;
-			m_entersound = true;
-		}
-		else
-		{
-			key_dest = key_game;
-			m_state = m_none;
-		}
-		break;
-
-	case 'Y':
-	case 'y':
-		key_dest = key_console;
-		Host_Quit_f ();
-		break;
-
-	default:
-		break;
-	}
-
-}
-
-
-void M_Quit_Draw (void)
-{
-	if (wasInMenus)
-	{
-		m_state = m_quit_prevstate;
-		m_recursiveDraw = true;
-		M_Draw ();
-		m_state = m_quit;
-	}
-
-#ifdef _WIN32
-	M_DrawTextBox (0, 0, 38, 23);
-	M_PrintWhite (16, 12,  "  Quake version 1.09 by id Software\n\n");
-	M_PrintWhite (16, 28,  "Programming        Art \n");
-	M_Print (16, 36,  " John Carmack       Adrian Carmack\n");
-	M_Print (16, 44,  " Michael Abrash     Kevin Cloud\n");
-	M_Print (16, 52,  " John Cash          Paul Steed\n");

-	M_Print (16, 60,  " Dave 'Zoid' Kirsch\n");
-	M_PrintWhite (16, 68,  "Design             Biz\n");
-	M_Print (16, 76,  " John Romero        Jay Wilbur\n");
-	M_Print (16, 84,  " Sandy Petersen     Mike Wilson\n");
-	M_Print (16, 92,  " American McGee     Donna Jackson\n");
-	M_Print (16, 100,  " Tim Willits        Todd Hollenshead\n");
-	M_PrintWhite (16, 108, "Support            Projects\n");
-	M_Print (16, 116, " Barrett Alexander  Shawn Green\n");

-	M_PrintWhite (16, 124, "Sound Effects\n");
-	M_Print (16, 132, " Trent Reznor and Nine Inch Nails\n\n");
-	M_PrintWhite (16, 140, "Quake is a trademark of Id Software,\n");
-	M_PrintWhite (16, 148, "inc., (c)1996 Id Software, inc. All\n");
-	M_PrintWhite (16, 156, "rights reserved. NIN logo is a\n");
-	M_PrintWhite (16, 164, "registered trademark licensed to\n");
-	M_PrintWhite (16, 172, "Nothing Interactive, Inc. All rights\n");
-	M_PrintWhite (16, 180, "reserved. Press y to exit\n");
-#else
-	M_DrawTextBox (56, 76, 24, 4);
-	M_Print (64, 84,  quitMessage[msgNumber*4+0]);
-	M_Print (64, 92,  quitMessage[msgNumber*4+1]);
-	M_Print (64, 100, quitMessage[msgNumber*4+2]);
-	M_Print (64, 108, quitMessage[msgNumber*4+3]);
-#endif
-}
-
-//=============================================================================
-
-/* SERIAL CONFIG MENU */
-
-int		serialConfig_cursor;
-int		serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
-#define	NUM_SERIALCONFIG_CMDS	6
-
-static int ISA_uarts[]	= {0x3f8,0x2f8,0x3e8,0x2e8};
-static int ISA_IRQs[]	= {4,3,4,3};
-int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
-
-int		serialConfig_comport;
-int		serialConfig_irq ;
-int		serialConfig_baud;
-char	serialConfig_phone[16];
-
-void M_Menu_SerialConfig_f (void)
-{
-	int		n;
-	int		port;
-	int		baudrate;
-	qboolean	useModem;
-
-	key_dest = key_menu;
-	m_state = m_serialconfig;
-	m_entersound = true;
-	if (JoiningGame && SerialConfig)
-		serialConfig_cursor = 4;
-	else
-		serialConfig_cursor = 5;
-
-	(*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
-
-	// map uart's port to COMx
-	for (n = 0; n < 4; n++)
-		if (ISA_uarts[n] == port)
-			break;
-	if (n == 4)
-	{
-		n = 0;
-		serialConfig_irq = 4;
-	}
-	serialConfig_comport = n + 1;
-
-	// map baudrate to index
-	for (n = 0; n < 6; n++)
-		if (serialConfig_baudrate[n] == baudrate)
-			break;
-	if (n == 6)
-		n = 5;
-	serialConfig_baud = n;
-
-	m_return_onerror = false;
-	m_return_reason[0] = 0;
-}
-
-
-void M_SerialConfig_Draw (void)
-{
-	qpic_t	*p;
-	int		basex;
-	char	*startJoin;
-	char	*directModem;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	basex = (320-p->width)/2;
-	M_DrawPic (basex, 4, p);
-
-	if (StartingGame)
-		startJoin = "New Game";
-	else
-		startJoin = "Join Game";
-	if (SerialConfig)
-		directModem = "Modem";
-	else
-		directModem = "Direct Connect";
-	M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
-	basex += 8;
-
-	M_Print (basex, serialConfig_cursor_table[0], "Port");
-	M_DrawTextBox (160, 40, 4, 1);
-	M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport));
-
-	M_Print (basex, serialConfig_cursor_table[1], "IRQ");
-	M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
-	M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq));
-
-	M_Print (basex, serialConfig_cursor_table[2], "Baud");
-	M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
-	M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud]));
-
-	if (SerialConfig)
-	{
-		M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
-		if (JoiningGame)
-		{
-			M_Print (basex, serialConfig_cursor_table[4], "Phone number");
-			M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
-			M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
-		}
-	}
-
-	if (JoiningGame)
-	{
-		M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
-		M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
-	}
-	else
-	{
-		M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
-		M_Print (basex+8, serialConfig_cursor_table[5], "OK");
-	}
-
-	M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
-
-	if (serialConfig_cursor == 4)
-		M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
-
-	if (*m_return_reason)
-		M_PrintWhite (basex, 148, m_return_reason);
-}
-
-
-void M_SerialConfig_Key (int key)
-{
-	int		l;
-
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_Net_f ();
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		serialConfig_cursor--;
-		if (serialConfig_cursor < 0)
-			serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		serialConfig_cursor++;
-		if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
-			serialConfig_cursor = 0;
-		break;
-
-	case K_LEFTARROW:
-		if (serialConfig_cursor > 2)
-			break;
-		S_LocalSound ("misc/menu3.wav");
-
-		if (serialConfig_cursor == 0)
-		{
-			serialConfig_comport--;
-			if (serialConfig_comport == 0)
-				serialConfig_comport = 4;
-			serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
-		}
-
-		if (serialConfig_cursor == 1)
-		{
-			serialConfig_irq--;
-			if (serialConfig_irq == 6)
-				serialConfig_irq = 5;
-			if (serialConfig_irq == 1)
-				serialConfig_irq = 7;
-		}
-
-		if (serialConfig_cursor == 2)
-		{
-			serialConfig_baud--;
-			if (serialConfig_baud < 0)
-				serialConfig_baud = 5;
-		}
-
-		break;
-
-	case K_RIGHTARROW:
-		if (serialConfig_cursor > 2)
-			break;
-forward:
-		S_LocalSound ("misc/menu3.wav");
-
-		if (serialConfig_cursor == 0)
-		{
-			serialConfig_comport++;
-			if (serialConfig_comport > 4)
-				serialConfig_comport = 1;
-			serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
-		}
-
-		if (serialConfig_cursor == 1)
-		{
-			serialConfig_irq++;
-			if (serialConfig_irq == 6)
-				serialConfig_irq = 7;
-			if (serialConfig_irq == 8)
-				serialConfig_irq = 2;
-		}
-
-		if (serialConfig_cursor == 2)
-		{
-			serialConfig_baud++;
-			if (serialConfig_baud > 5)
-				serialConfig_baud = 0;
-		}
-
-		break;
-
-	case K_ENTER:
-		if (serialConfig_cursor < 3)
-			goto forward;
-
-		m_entersound = true;
-
-		if (serialConfig_cursor == 3)
-		{
-			(*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
-
-			M_Menu_ModemConfig_f ();
-			break;
-		}
-
-		if (serialConfig_cursor == 4)
-		{
-			serialConfig_cursor = 5;
-			break;
-		}
-
-		// serialConfig_cursor == 5 (OK/CONNECT)
-		(*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
-
-		M_ConfigureNetSubsystem ();
-
-		if (StartingGame)
-		{
-			M_Menu_GameOptions_f ();
-			break;
-		}
-
-		m_return_state = m_state;
-		m_return_onerror = true;
-		key_dest = key_game;
-		m_state = m_none;
-
-		if (SerialConfig)
-			Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
-		else
-			Cbuf_AddText ("connect\n");
-		break;
-
-	case K_BACKSPACE:
-		if (serialConfig_cursor == 4)
-		{
-			if (strlen(serialConfig_phone))
-				serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
-		}
-		break;
-
-	default:
-		if (key < 32 || key > 127)
-			break;
-		if (serialConfig_cursor == 4)
-		{
-			l = strlen(serialConfig_phone);
-			if (l < 15)
-			{
-				serialConfig_phone[l+1] = 0;
-				serialConfig_phone[l] = key;
-			}
-		}
-	}
-
-	if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
-		if (key == K_UPARROW)
-			serialConfig_cursor = 2;
-		else
-			serialConfig_cursor = 5;
-
-	if (SerialConfig && StartingGame && serialConfig_cursor == 4)
-		if (key == K_UPARROW)
-			serialConfig_cursor = 3;
-		else
-			serialConfig_cursor = 5;
-}
-
-//=============================================================================
-/* MODEM CONFIG MENU */
-
-int		modemConfig_cursor;
-int		modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
-#define NUM_MODEMCONFIG_CMDS	5
-
-char	modemConfig_dialing;
-char	modemConfig_clear [16];
-char	modemConfig_init [32];
-char	modemConfig_hangup [16];
-
-void M_Menu_ModemConfig_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_modemconfig;
-	m_entersound = true;
-	(*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
-}
-
-
-void M_ModemConfig_Draw (void)
-{
-	qpic_t	*p;
-	int		basex;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	basex = (320-p->width)/2;
-	M_DrawPic (basex, 4, p);
-	basex += 8;
-
-	if (modemConfig_dialing == 'P')
-		M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
-	else
-		M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
-
-	M_Print (basex, modemConfig_cursor_table[1], "Clear");
-	M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
-	M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
-	if (modemConfig_cursor == 1)
-		M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
-
-	M_Print (basex, modemConfig_cursor_table[2], "Init");
-	M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
-	M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
-	if (modemConfig_cursor == 2)
-		M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
-
-	M_Print (basex, modemConfig_cursor_table[3], "Hangup");
-	M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
-	M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
-	if (modemConfig_cursor == 3)
-		M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
-
-	M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
-	M_Print (basex+8, modemConfig_cursor_table[4], "OK");
-
-	M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
-}
-
-
-void M_ModemConfig_Key (int key)
-{
-	int		l;
-
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_SerialConfig_f ();
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		modemConfig_cursor--;
-		if (modemConfig_cursor < 0)
-			modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		modemConfig_cursor++;
-		if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
-			modemConfig_cursor = 0;
-		break;
-
-	case K_LEFTARROW:
-	case K_RIGHTARROW:
-		if (modemConfig_cursor == 0)
-		{
-			if (modemConfig_dialing == 'P')
-				modemConfig_dialing = 'T';
-			else
-				modemConfig_dialing = 'P';
-			S_LocalSound ("misc/menu1.wav");
-		}
-		break;
-
-	case K_ENTER:
-		if (modemConfig_cursor == 0)
-		{
-			if (modemConfig_dialing == 'P')
-				modemConfig_dialing = 'T';
-			else
-				modemConfig_dialing = 'P';
-			m_entersound = true;
-		}
-
-		if (modemConfig_cursor == 4)
-		{
-			(*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
-			m_entersound = true;
-			M_Menu_SerialConfig_f ();
-		}
-		break;
-
-	case K_BACKSPACE:
-		if (modemConfig_cursor == 1)
-		{
-			if (strlen(modemConfig_clear))
-				modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
-		}
-
-		if (modemConfig_cursor == 2)
-		{
-			if (strlen(modemConfig_init))
-				modemConfig_init[strlen(modemConfig_init)-1] = 0;
-		}
-
-		if (modemConfig_cursor == 3)
-		{
-			if (strlen(modemConfig_hangup))
-				modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
-		}
-		break;
-
-	default:
-		if (key < 32 || key > 127)
-			break;
-
-		if (modemConfig_cursor == 1)
-		{
-			l = strlen(modemConfig_clear);
-			if (l < 15)
-			{
-				modemConfig_clear[l+1] = 0;
-				modemConfig_clear[l] = key;
-			}
-		}
-
-		if (modemConfig_cursor == 2)
-		{
-			l = strlen(modemConfig_init);
-			if (l < 29)
-			{
-				modemConfig_init[l+1] = 0;
-				modemConfig_init[l] = key;
-			}
-		}
-
-		if (modemConfig_cursor == 3)
-		{
-			l = strlen(modemConfig_hangup);
-			if (l < 15)
-			{
-				modemConfig_hangup[l+1] = 0;
-				modemConfig_hangup[l] = key;
-			}
-		}
-	}
-}
-
-//=============================================================================
-/* LAN CONFIG MENU */
-
-int		lanConfig_cursor = -1;
-int		lanConfig_cursor_table [] = {72, 92, 124};
-#define NUM_LANCONFIG_CMDS	3
-
-int 	lanConfig_port;
-char	lanConfig_portname[6];
-char	lanConfig_joinname[22];
-
-void M_Menu_LanConfig_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_lanconfig;
-	m_entersound = true;
-	if (lanConfig_cursor == -1)
-	{
-		if (JoiningGame && TCPIPConfig)
-			lanConfig_cursor = 2;
-		else
-			lanConfig_cursor = 1;
-	}
-	if (StartingGame && lanConfig_cursor == 2)
-		lanConfig_cursor = 1;
-	lanConfig_port = DEFAULTnet_hostport;
-	sprintf(lanConfig_portname, "%u", lanConfig_port);
-
-	m_return_onerror = false;
-	m_return_reason[0] = 0;
-}
-
-
-void M_LanConfig_Draw (void)
-{
-	qpic_t	*p;
-	int		basex;
-	char	*startJoin;
-	char	*protocol;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	basex = (320-p->width)/2;
-	M_DrawPic (basex, 4, p);
-
-	if (StartingGame)
-		startJoin = "New Game";
-	else
-		startJoin = "Join Game";
-	if (IPXConfig)
-		protocol = "IPX";
-	else
-		protocol = "TCP/IP";
-	M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
-	basex += 8;
-
-	M_Print (basex, 52, "Address:");
-	if (IPXConfig)
-		M_Print (basex+9*8, 52, my_ipx_address);
-	else
-		M_Print (basex+9*8, 52, my_tcpip_address);
-
-	M_Print (basex, lanConfig_cursor_table[0], "Port");
-	M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
-	M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
-
-	if (JoiningGame)
-	{
-		M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
-		M_Print (basex, 108, "Join game at:");
-		M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
-		M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
-	}
-	else
-	{
-		M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1);
-		M_Print (basex+8, lanConfig_cursor_table[1], "OK");
-	}
-
-	M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));
-
-	if (lanConfig_cursor == 0)
-		M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
-
-	if (lanConfig_cursor == 2)
-		M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
-
-	if (*m_return_reason)
-		M_PrintWhite (basex, 148, m_return_reason);
-}
-
-
-void M_LanConfig_Key (int key)
-{
-	int		l;
-
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_Net_f ();
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		lanConfig_cursor--;
-		if (lanConfig_cursor < 0)
-			lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		lanConfig_cursor++;
-		if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
-			lanConfig_cursor = 0;
-		break;
-
-	case K_ENTER:
-		if (lanConfig_cursor == 0)
-			break;
-
-		m_entersound = true;
-
-		M_ConfigureNetSubsystem ();
-
-		if (lanConfig_cursor == 1)
-		{
-			if (StartingGame)
-			{
-				M_Menu_GameOptions_f ();
-				break;
-			}
-			M_Menu_Search_f();
-			break;
-		}
-
-		if (lanConfig_cursor == 2)
-		{
-			m_return_state = m_state;
-			m_return_onerror = true;
-			key_dest = key_game;
-			m_state = m_none;
-			Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
-			break;
-		}
-
-		break;
-
-	case K_BACKSPACE:
-		if (lanConfig_cursor == 0)
-		{
-			if (strlen(lanConfig_portname))
-				lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
-		}
-
-		if (lanConfig_cursor == 2)
-		{
-			if (strlen(lanConfig_joinname))
-				lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
-		}
-		break;
-
-	default:
-		if (key < 32 || key > 127)
-			break;
-
-		if (lanConfig_cursor == 2)
-		{
-			l = strlen(lanConfig_joinname);
-			if (l < 21)
-			{
-				lanConfig_joinname[l+1] = 0;
-				lanConfig_joinname[l] = key;
-			}
-		}
-
-		if (key < '0' || key > '9')
-			break;
-		if (lanConfig_cursor == 0)
-		{
-			l = strlen(lanConfig_portname);
-			if (l < 5)
-			{
-				lanConfig_portname[l+1] = 0;
-				lanConfig_portname[l] = key;
-			}
-		}
-	}
-
-	if (StartingGame && lanConfig_cursor == 2)
-		if (key == K_UPARROW)
-			lanConfig_cursor = 1;
-		else
-			lanConfig_cursor = 0;
-
-	l =  Q_atoi(lanConfig_portname);
-	if (l > 65535)
-		l = lanConfig_port;
-	else
-		lanConfig_port = l;
-	sprintf(lanConfig_portname, "%u", lanConfig_port);
-}
-
-//=============================================================================
-/* GAME OPTIONS MENU */
-
-typedef struct
-{
-	char	*name;
-	char	*description;
-} level_t;
-
-level_t		levels[] =
-{
-	{"start", "Entrance"},	// 0
-
-	{"e1m1", "Slipgate Complex"},				// 1
-	{"e1m2", "Castle of the Damned"},
-	{"e1m3", "The Necropolis"},
-	{"e1m4", "The Grisly Grotto"},
-	{"e1m5", "Gloom Keep"},
-	{"e1m6", "The Door To Chthon"},
-	{"e1m7", "The House of Chthon"},
-	{"e1m8", "Ziggurat Vertigo"},
-
-	{"e2m1", "The Installation"},				// 9
-	{"e2m2", "Ogre Citadel"},
-	{"e2m3", "Crypt of Decay"},
-	{"e2m4", "The Ebon Fortress"},
-	{"e2m5", "The Wizard's Manse"},
-	{"e2m6", "The Dismal Oubliette"},
-	{"e2m7", "Underearth"},
-
-	{"e3m1", "Termination Central"},			// 16
-	{"e3m2", "The Vaults of Zin"},
-	{"e3m3", "The Tomb of Terror"},
-	{"e3m4", "Satan's Dark Delight"},
-	{"e3m5", "Wind Tunnels"},
-	{"e3m6", "Chambers of Torment"},
-	{"e3m7", "The Haunted Halls"},
-
-	{"e4m1", "The Sewage System"},				// 23
-	{"e4m2", "The Tower of Despair"},
-	{"e4m3", "The Elder God Shrine"},
-	{"e4m4", "The Palace of Hate"},
-	{"e4m5", "Hell's Atrium"},
-	{"e4m6", "The Pain Maze"},
-	{"e4m7", "Azure Agony"},
-	{"e4m8", "The Nameless City"},
-
-	{"end", "Shub-Niggurath's Pit"},			// 31
-
-	{"dm1", "Place of Two Deaths"},				// 32
-	{"dm2", "Claustrophobopolis"},
-	{"dm3", "The Abandoned Base"},
-	{"dm4", "The Bad Place"},
-	{"dm5", "The Cistern"},
-	{"dm6", "The Dark Zone"}
-};
-
-//MED 01/06/97 added hipnotic levels
-level_t     hipnoticlevels[] =
-{
-   {"start", "Command HQ"},  // 0
-
-   {"hip1m1", "The Pumping Station"},          // 1
-   {"hip1m2", "Storage Facility"},
-   {"hip1m3", "The Lost Mine"},
-   {"hip1m4", "Research Facility"},
-   {"hip1m5", "Military Complex"},
-
-   {"hip2m1", "Ancient Realms"},          // 6
-   {"hip2m2", "The Black Cathedral"},
-   {"hip2m3", "The Catacombs"},
-   {"hip2m4", "The Crypt"},
-   {"hip2m5", "Mortum's Keep"},
-   {"hip2m6", "The Gremlin's Domain"},
-
-   {"hip3m1", "Tur Torment"},       // 12
-   {"hip3m2", "Pandemonium"},
-   {"hip3m3", "Limbo"},
-   {"hip3m4", "The Gauntlet"},
-
-   {"hipend", "Armagon's Lair"},       // 16
-
-   {"hipdm1", "The Edge of Oblivion"}           // 17
-};
-
-//PGM 01/07/97 added rogue levels
-//PGM 03/02/97 added dmatch level
-level_t		roguelevels[] =
-{
-	{"start",	"Split Decision"},
-	{"r1m1",	"Deviant's Domain"},
-	{"r1m2",	"Dread Portal"},
-	{"r1m3",	"Judgement Call"},
-	{"r1m4",	"Cave of Death"},
-	{"r1m5",	"Towers of Wrath"},
-	{"r1m6",	"Temple of Pain"},
-	{"r1m7",	"Tomb of the Overlord"},
-	{"r2m1",	"Tempus Fugit"},
-	{"r2m2",	"Elemental Fury I"},
-	{"r2m3",	"Elemental Fury II"},
-	{"r2m4",	"Curse of Osiris"},
-	{"r2m5",	"Wizard's Keep"},
-	{"r2m6",	"Blood Sacrifice"},
-	{"r2m7",	"Last Bastion"},
-	{"r2m8",	"Source of Evil"},
-	{"ctf1",    "Division of Change"}
-};
-
-typedef struct
-{
-	char	*description;
-	int		firstLevel;
-	int		levels;
-} episode_t;
-
-episode_t	episodes[] =
-{
-	{"Welcome to Quake", 0, 1},
-	{"Doomed Dimension", 1, 8},
-	{"Realm of Black Magic", 9, 7},
-	{"Netherworld", 16, 7},
-	{"The Elder World", 23, 8},
-	{"Final Level", 31, 1},
-	{"Deathmatch Arena", 32, 6}
-};
-
-//MED 01/06/97  added hipnotic episodes
-episode_t   hipnoticepisodes[] =
-{
-   {"Scourge of Armagon", 0, 1},
-   {"Fortress of the Dead", 1, 5},
-   {"Dominion of Darkness", 6, 6},
-   {"The Rift", 12, 4},
-   {"Final Level", 16, 1},
-   {"Deathmatch Arena", 17, 1}
-};
-
-//PGM 01/07/97 added rogue episodes
-//PGM 03/02/97 added dmatch episode
-episode_t	rogueepisodes[] =
-{
-	{"Introduction", 0, 1},
-	{"Hell's Fortress", 1, 7},
-	{"Corridors of Time", 8, 8},
-	{"Deathmatch Arena", 16, 1}
-};
-
-int	startepisode;
-int	startlevel;
-int maxplayers;
-qboolean m_serverInfoMessage = false;
-double m_serverInfoMessageTime;
-
-void M_Menu_GameOptions_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_gameoptions;
-	m_entersound = true;
-	if (maxplayers == 0)
-		maxplayers = svs.maxclients;
-	if (maxplayers < 2)
-		maxplayers = svs.maxclientslimit;
-}
-
-
-int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
-#define	NUM_GAMEOPTIONS	9
-int		gameoptions_cursor;
-
-void M_GameOptions_Draw (void)
-{
-	qpic_t	*p;
-	int		x;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-
-	M_DrawTextBox (152, 32, 10, 1);
-	M_Print (160, 40, "begin game");
-
-	M_Print (0, 56, "      Max players");
-	M_Print (160, 56, va("%i", maxplayers) );
-
-	M_Print (0, 64, "        Game Type");
-	if (coop.value)
-		M_Print (160, 64, "Cooperative");
-	else
-		M_Print (160, 64, "Deathmatch");
-
-	M_Print (0, 72, "        Teamplay");
-	if (rogue)
-	{
-		char *msg;
-
-		switch((int)teamplay.value)
-		{
-			case 1: msg = "No Friendly Fire"; break;
-			case 2: msg = "Friendly Fire"; break;
-			case 3: msg = "Tag"; break;
-			case 4: msg = "Capture the Flag"; break;
-			case 5: msg = "One Flag CTF"; break;
-			case 6: msg = "Three Team CTF"; break;
-			default: msg = "Off"; break;
-		}
-		M_Print (160, 72, msg);
-	}
-	else
-	{
-		char *msg;
-
-		switch((int)teamplay.value)
-		{
-			case 1: msg = "No Friendly Fire"; break;
-			case 2: msg = "Friendly Fire"; break;
-			default: msg = "Off"; break;
-		}
-		M_Print (160, 72, msg);
-	}
-
-	M_Print (0, 80, "            Skill");
-	if (skill.value == 0)
-		M_Print (160, 80, "Easy difficulty");
-	else if (skill.value == 1)
-		M_Print (160, 80, "Normal difficulty");
-	else if (skill.value == 2)
-		M_Print (160, 80, "Hard difficulty");
-	else
-		M_Print (160, 80, "Nightmare difficulty");
-
-	M_Print (0, 88, "       Frag Limit");
-	if (fraglimit.value == 0)
-		M_Print (160, 88, "none");
-	else
-		M_Print (160, 88, va("%i frags", (int)fraglimit.value));
-
-	M_Print (0, 96, "       Time Limit");
-	if (timelimit.value == 0)
-		M_Print (160, 96, "none");
-	else
-		M_Print (160, 96, va("%i minutes", (int)timelimit.value));
-
-	M_Print (0, 112, "         Episode");
-   //MED 01/06/97 added hipnotic episodes
-   if (hipnotic)
-      M_Print (160, 112, hipnoticepisodes[startepisode].description);
-   //PGM 01/07/97 added rogue episodes
-   else if (rogue)
-      M_Print (160, 112, rogueepisodes[startepisode].description);
-   else
-      M_Print (160, 112, episodes[startepisode].description);
-
-	M_Print (0, 120, "           Level");
-   //MED 01/06/97 added hipnotic episodes
-   if (hipnotic)
-   {
-      M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
-      M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
-   }
-   //PGM 01/07/97 added rogue episodes
-   else if (rogue)
-   {
-      M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
-      M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
-   }
-   else
-   {
-      M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
-      M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
-   }
-
-// line cursor
-	M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
-
-	if (m_serverInfoMessage)
-	{
-		if ((realtime - m_serverInfoMessageTime) < 5.0)
-		{
-			x = (320-26*8)/2;
-			M_DrawTextBox (x, 138, 24, 4);
-			x += 8;
-			M_Print (x, 146, "  More than 4 players   ");
-			M_Print (x, 154, " requires using command ");
-			M_Print (x, 162, "line parameters; please ");
-			M_Print (x, 170, "   see techinfo.txt.    ");
-		}
-		else
-		{
-			m_serverInfoMessage = false;
-		}
-	}
-}
-
-
-void M_NetStart_Change (int dir)
-{
-	int count;
-
-	switch (gameoptions_cursor)
-	{
-	case 1:
-		maxplayers += dir;
-		if (maxplayers > svs.maxclientslimit)
-		{
-			maxplayers = svs.maxclientslimit;
-			m_serverInfoMessage = true;
-			m_serverInfoMessageTime = realtime;
-		}
-		if (maxplayers < 2)
-			maxplayers = 2;
-		break;
-
-	case 2:
-		Cvar_SetValue ("coop", coop.value ? 0 : 1);
-		break;
-
-	case 3:
-		if (rogue)
-			count = 6;
-		else
-			count = 2;
-
-		Cvar_SetValue ("teamplay", teamplay.value + dir);
-		if (teamplay.value > count)
-			Cvar_SetValue ("teamplay", 0);
-		else if (teamplay.value < 0)
-			Cvar_SetValue ("teamplay", count);
-		break;
-
-	case 4:
-		Cvar_SetValue ("skill", skill.value + dir);
-		if (skill.value > 3)
-			Cvar_SetValue ("skill", 0);
-		if (skill.value < 0)
-			Cvar_SetValue ("skill", 3);
-		break;
-
-	case 5:
-		Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
-		if (fraglimit.value > 100)
-			Cvar_SetValue ("fraglimit", 0);
-		if (fraglimit.value < 0)
-			Cvar_SetValue ("fraglimit", 100);
-		break;
-
-	case 6:
-		Cvar_SetValue ("timelimit", timelimit.value + dir*5);
-		if (timelimit.value > 60)
-			Cvar_SetValue ("timelimit", 0);
-		if (timelimit.value < 0)
-			Cvar_SetValue ("timelimit", 60);
-		break;
-
-	case 7:
-		startepisode += dir;
-	//MED 01/06/97 added hipnotic count
-		if (hipnotic)
-			count = 6;
-	//PGM 01/07/97 added rogue count
-	//PGM 03/02/97 added 1 for dmatch episode
-		else if (rogue)
-			count = 4;
-		else if (registered.value)
-			count = 7;
-		else
-			count = 2;
-
-		if (startepisode < 0)
-			startepisode = count - 1;
-
-		if (startepisode >= count)
-			startepisode = 0;
-
-		startlevel = 0;
-		break;
-
-	case 8:
-		startlevel += dir;
-    //MED 01/06/97 added hipnotic episodes
-		if (hipnotic)
-			count = hipnoticepisodes[startepisode].levels;
-	//PGM 01/06/97 added hipnotic episodes
-		else if (rogue)
-			count = rogueepisodes[startepisode].levels;
-		else
-			count = episodes[startepisode].levels;
-
-		if (startlevel < 0)
-			startlevel = count - 1;
-
-		if (startlevel >= count)
-			startlevel = 0;
-		break;
-	}
-}
-
-void M_GameOptions_Key (int key)
-{
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_Net_f ();
-		break;
-
-	case K_UPARROW:
-		S_LocalSound ("misc/menu1.wav");
-		gameoptions_cursor--;
-		if (gameoptions_cursor < 0)
-			gameoptions_cursor = NUM_GAMEOPTIONS-1;
-		break;
-
-	case K_DOWNARROW:
-		S_LocalSound ("misc/menu1.wav");
-		gameoptions_cursor++;
-		if (gameoptions_cursor >= NUM_GAMEOPTIONS)
-			gameoptions_cursor = 0;
-		break;
-
-	case K_LEFTARROW:
-		if (gameoptions_cursor == 0)
-			break;
-		S_LocalSound ("misc/menu3.wav");
-		M_NetStart_Change (-1);
-		break;
-
-	case K_RIGHTARROW:
-		if (gameoptions_cursor == 0)
-			break;
-		S_LocalSound ("misc/menu3.wav");
-		M_NetStart_Change (1);
-		break;
-
-	case K_ENTER:
-		S_LocalSound ("misc/menu2.wav");
-		if (gameoptions_cursor == 0)
-		{
-			if (sv.active)
-				Cbuf_AddText ("disconnect\n");
-			Cbuf_AddText ("listen 0\n");	// so host_netport will be re-examined
-			Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
-			SCR_BeginLoadingPlaque ();
-
-			if (hipnotic)
-				Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );
-			else if (rogue)
-				Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );
-			else
-				Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) );
-
-			return;
-		}
-
-		M_NetStart_Change (1);
-		break;
-	}
-}
-
-//=============================================================================
-/* SEARCH MENU */
-
-qboolean	searchComplete = false;
-double		searchCompleteTime;
-
-void M_Menu_Search_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_search;
-	m_entersound = false;
-	slistSilent = true;
-	slistLocal = false;
-	searchComplete = false;
-	NET_Slist_f();
-
-}
-
-
-void M_Search_Draw (void)
-{
-	qpic_t	*p;
-	int x;
-
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-	x = (320/2) - ((12*8)/2) + 4;
-	M_DrawTextBox (x-8, 32, 12, 1);
-	M_Print (x, 40, "Searching...");
-
-	if(slistInProgress)
-	{
-		NET_Poll();
-		return;
-	}
-
-	if (! searchComplete)
-	{
-		searchComplete = true;
-		searchCompleteTime = realtime;
-	}
-
-	if (hostCacheCount)
-	{
-		M_Menu_ServerList_f ();
-		return;
-	}
-
-	M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
-	if ((realtime - searchCompleteTime) < 3.0)
-		return;
-
-	M_Menu_LanConfig_f ();
-}
-
-
-void M_Search_Key (int key)
-{
-}
-
-//=============================================================================
-/* SLIST MENU */
-
-int		slist_cursor;
-qboolean slist_sorted;
-
-void M_Menu_ServerList_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_slist;
-	m_entersound = true;
-	slist_cursor = 0;
-	m_return_onerror = false;
-	m_return_reason[0] = 0;
-	slist_sorted = false;
-}
-
-
-void M_ServerList_Draw (void)
-{
-	int		n;
-	char	string [64];
-	qpic_t	*p;
-
-	if (!slist_sorted)
-	{
-		if (hostCacheCount > 1)
-		{
-			int	i,j;
-			hostcache_t temp;
-			for (i = 0; i < hostCacheCount; i++)
-				for (j = i+1; j < hostCacheCount; j++)
-					if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
-					{
-						Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
-						Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
-						Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
-					}
-		}
-		slist_sorted = true;
-	}
-
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-	for (n = 0; n < hostCacheCount; n++)
-	{
-		if (hostcache[n].maxusers)
-			sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
-		else
-			sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
-		M_Print (16, 32 + 8*n, string);
-	}
-	M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
-
-	if (*m_return_reason)
-		M_PrintWhite (16, 148, m_return_reason);
-}
-
-
-void M_ServerList_Key (int k)
-{
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_LanConfig_f ();
-		break;
-
-	case K_SPACE:
-		M_Menu_Search_f ();
-		break;
-
-	case K_UPARROW:
-	case K_LEFTARROW:
-		S_LocalSound ("misc/menu1.wav");
-		slist_cursor--;
-		if (slist_cursor < 0)
-			slist_cursor = hostCacheCount - 1;
-		break;
-
-	case K_DOWNARROW:
-	case K_RIGHTARROW:
-		S_LocalSound ("misc/menu1.wav");
-		slist_cursor++;
-		if (slist_cursor >= hostCacheCount)
-			slist_cursor = 0;
-		break;
-
-	case K_ENTER:
-		S_LocalSound ("misc/menu2.wav");
-		m_return_state = m_state;
-		m_return_onerror = true;
-		slist_sorted = false;
-		key_dest = key_game;
-		m_state = m_none;
-		Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
-		break;
-
-	default:
-		break;
-	}
-
-}
-
-//=============================================================================
-/* Menu Subsystem */
-
-
-void M_Init (void)
-{
-	Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
-
-	Cmd_AddCommand ("menu_main", M_Menu_Main_f);
-	Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
-	Cmd_AddCommand ("menu_load", M_Menu_Load_f);
-	Cmd_AddCommand ("menu_save", M_Menu_Save_f);
-	Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
-	Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
-	Cmd_AddCommand ("menu_options", M_Menu_Options_f);
-	Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
-	Cmd_AddCommand ("menu_video", M_Menu_Video_f);
-	Cmd_AddCommand ("help", M_Menu_Help_f);
-	Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
-}
-
-
-void M_Draw (void)
-{
-	if (m_state == m_none || key_dest != key_menu)
-		return;
-
-	if (!m_recursiveDraw)
-	{
-		scr_copyeverything = 1;
-
-		if (scr_con_current)
-		{
-			Draw_ConsoleBackground (vid.height);
-			VID_UnlockBuffer ();
-			S_ExtraUpdate ();
-			VID_LockBuffer ();
-		}
-		else
-			Draw_FadeScreen ();
-
-		scr_fullupdate = 0;
-	}
-	else
-	{
-		m_recursiveDraw = false;
-	}
-
-	switch (m_state)
-	{
-	case m_none:
-		break;
-
-	case m_main:
-		M_Main_Draw ();
-		break;
-
-	case m_singleplayer:
-		M_SinglePlayer_Draw ();
-		break;
-
-	case m_load:
-		M_Load_Draw ();
-		break;
-
-	case m_save:
-		M_Save_Draw ();
-		break;
-
-	case m_multiplayer:
-		M_MultiPlayer_Draw ();
-		break;
-
-	case m_setup:
-		M_Setup_Draw ();
-		break;
-
-	case m_net:
-		M_Net_Draw ();
-		break;
-
-	case m_options:
-		M_Options_Draw ();
-		break;
-
-	case m_keys:
-		M_Keys_Draw ();
-		break;
-
-	case m_video:
-		M_Video_Draw ();
-		break;
-
-	case m_help:
-		M_Help_Draw ();
-		break;
-
-	case m_quit:
-		M_Quit_Draw ();
-		break;
-
-	case m_serialconfig:
-		M_SerialConfig_Draw ();
-		break;
-
-	case m_modemconfig:
-		M_ModemConfig_Draw ();
-		break;
-
-	case m_lanconfig:
-		M_LanConfig_Draw ();
-		break;
-
-	case m_gameoptions:
-		M_GameOptions_Draw ();
-		break;
-
-	case m_search:
-		M_Search_Draw ();
-		break;
-
-	case m_slist:
-		M_ServerList_Draw ();
-		break;
-	}
-
-	if (m_entersound)
-	{
-		S_LocalSound ("misc/menu2.wav");
-		m_entersound = false;
-	}
-
-	VID_UnlockBuffer ();
-	S_ExtraUpdate ();
-	VID_LockBuffer ();
-}
-
-
-void M_Keydown (int key)
-{
-	switch (m_state)
-	{
-	case m_none:
-		return;
-
-	case m_main:
-		M_Main_Key (key);
-		return;
-
-	case m_singleplayer:
-		M_SinglePlayer_Key (key);
-		return;
-
-	case m_load:
-		M_Load_Key (key);
-		return;
-
-	case m_save:
-		M_Save_Key (key);
-		return;
-
-	case m_multiplayer:
-		M_MultiPlayer_Key (key);
-		return;
-
-	case m_setup:
-		M_Setup_Key (key);
-		return;
-
-	case m_net:
-		M_Net_Key (key);
-		return;
-
-	case m_options:
-		M_Options_Key (key);
-		return;
-
-	case m_keys:
-		M_Keys_Key (key);
-		return;
-
-	case m_video:
-		M_Video_Key (key);
-		return;
-
-	case m_help:
-		M_Help_Key (key);
-		return;
-
-	case m_quit:
-		M_Quit_Key (key);
-		return;
-
-	case m_serialconfig:
-		M_SerialConfig_Key (key);
-		return;
-
-	case m_modemconfig:
-		M_ModemConfig_Key (key);
-		return;
-
-	case m_lanconfig:
-		M_LanConfig_Key (key);
-		return;
-
-	case m_gameoptions:
-		M_GameOptions_Key (key);
-		return;
-
-	case m_search:
-		M_Search_Key (key);
-		break;
-
-	case m_slist:
-		M_ServerList_Key (key);
-		return;
-	}
-}
-
-
-void M_ConfigureNetSubsystem(void)
-{
-// enable/disable net systems to match desired config
-
-	Cbuf_AddText ("stopdemo\n");
-	if (SerialConfig || DirectConfig)
-	{
-		Cbuf_AddText ("com1 enable\n");
-	}
-
-	if (IPXConfig || TCPIPConfig)
-		net_hostport = lanConfig_port;
-}
diff --git a/quake/src/WinQuake/menu.cpp b/quake/src/WinQuake/menu.cpp
new file mode 100755
index 0000000..b23a394
--- /dev/null
+++ b/quake/src/WinQuake/menu.cpp
@@ -0,0 +1,3241 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+#include "quakedef.h"
+
+#ifdef _WIN32
+#include "winquake.h"
+#endif
+
+void (*vid_menudrawfn)(void);
+void (*vid_menukeyfn)(int key);
+
+enum m_state_t {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state;
+
+void M_Menu_Main_f (void);
+  void M_Menu_SinglePlayer_f (void);
+    void M_Menu_Load_f (void);
+    void M_Menu_Save_f (void);
+  void M_Menu_MultiPlayer_f (void);
+    void M_Menu_Setup_f (void);
+    void M_Menu_Net_f (void);
+  void M_Menu_Options_f (void);
+    void M_Menu_Keys_f (void);
+    void M_Menu_Video_f (void);
+  void M_Menu_Help_f (void);
+  void M_Menu_Quit_f (void);
+void M_Menu_SerialConfig_f (void);
+  void M_Menu_ModemConfig_f (void);
+void M_Menu_LanConfig_f (void);
+void M_Menu_GameOptions_f (void);
+void M_Menu_Search_f (void);
+void M_Menu_ServerList_f (void);
+
+void M_Main_Draw (void);
+  void M_SinglePlayer_Draw (void);
+    void M_Load_Draw (void);
+    void M_Save_Draw (void);
+  void M_MultiPlayer_Draw (void);
+    void M_Setup_Draw (void);
+    void M_Net_Draw (void);
+  void M_Options_Draw (void);
+    void M_Keys_Draw (void);
+    void M_Video_Draw (void);
+  void M_Help_Draw (void);
+  void M_Quit_Draw (void);
+void M_SerialConfig_Draw (void);
+  void M_ModemConfig_Draw (void);
+void M_LanConfig_Draw (void);
+void M_GameOptions_Draw (void);
+void M_Search_Draw (void);
+void M_ServerList_Draw (void);
+
+void M_Main_Key (int key);
+  void M_SinglePlayer_Key (int key);
+    void M_Load_Key (int key);
+    void M_Save_Key (int key);
+  void M_MultiPlayer_Key (int key);
+    void M_Setup_Key (int key);
+    void M_Net_Key (int key);
+  void M_Options_Key (int key);
+    void M_Keys_Key (int key);
+    void M_Video_Key (int key);
+  void M_Help_Key (int key);
+  void M_Quit_Key (int key);
+void M_SerialConfig_Key (int key);
+  void M_ModemConfig_Key (int key);
+void M_LanConfig_Key (int key);
+void M_GameOptions_Key (int key);
+void M_Search_Key (int key);
+void M_ServerList_Key (int key);
+
+qboolean	m_entersound;		// play after drawing a frame, so caching
+                // won't disrupt the sound
+qboolean	m_recursiveDraw;
+
+int			m_return_state;
+qboolean	m_return_onerror;
+char		m_return_reason [32];
+
+#define StartingGame	(m_multiplayer_cursor == 1)
+#define JoiningGame		(m_multiplayer_cursor == 0)
+#define SerialConfig	(m_net_cursor == 0)
+#define DirectConfig	(m_net_cursor == 1)
+#define	IPXConfig		(m_net_cursor == 2)
+#define	TCPIPConfig		(m_net_cursor == 3)
+
+void M_ConfigureNetSubsystem(void);
+
+/*
+================
+M_DrawCharacter
+
+Draws one solid graphics character
+================
+*/
+void M_DrawCharacter (int cx, int line, int num)
+{
+  Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
+}
+
+void M_Print (int cx, int cy, const char *str)
+{
+  while (*str)
+  {
+    M_DrawCharacter (cx, cy, (*str)+128);
+    str++;
+    cx += 8;
+  }
+}
+
+void M_PrintWhite (int cx, int cy, const char *str)
+{
+  while (*str)
+  {
+    M_DrawCharacter (cx, cy, *str);
+    str++;
+    cx += 8;
+  }
+}
+
+void M_DrawTransPic (int x, int y, qpic_t *pic)
+{
+  Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
+}
+
+void M_DrawPic (int x, int y, qpic_t *pic)
+{
+  Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
+}
+
+byte identityTable[256];
+byte translationTable[256];
+
+void M_BuildTranslationTable(int top, int bottom)
+{
+  int		j;
+  byte	*dest, *source;
+
+  for (j = 0; j < 256; j++)
+    identityTable[j] = j;
+  dest = translationTable;
+  source = identityTable;
+  memcpy (dest, source, 256);
+
+  if (top < 128)	// the artists made some backwards ranges.  sigh.
+    memcpy (dest + TOP_RANGE, source + top, 16);
+  else
+    for (j=0 ; j<16 ; j++)
+      dest[TOP_RANGE+j] = source[top+15-j];
+
+  if (bottom < 128)
+    memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
+  else
+    for (j=0 ; j<16 ; j++)
+      dest[BOTTOM_RANGE+j] = source[bottom+15-j];
+}
+
+
+void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
+{
+  Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
+}
+
+
+void M_DrawTextBox (int x, int y, int width, int lines)
+{
+  qpic_t	*p;
+  int		cx, cy;
+  int		n;
+
+  // draw left side
+  cx = x;
+  cy = y;
+  p = Draw_CachePic ("gfx/box_tl.lmp");
+  M_DrawTransPic (cx, cy, p);
+  p = Draw_CachePic ("gfx/box_ml.lmp");
+  for (n = 0; n < lines; n++)
+  {
+    cy += 8;
+    M_DrawTransPic (cx, cy, p);
+  }
+  p = Draw_CachePic ("gfx/box_bl.lmp");
+  M_DrawTransPic (cx, cy+8, p);
+
+  // draw middle
+  cx += 8;
+  while (width > 0)
+  {
+    cy = y;
+    p = Draw_CachePic ("gfx/box_tm.lmp");
+    M_DrawTransPic (cx, cy, p);
+    p = Draw_CachePic ("gfx/box_mm.lmp");
+    for (n = 0; n < lines; n++)
+    {
+      cy += 8;
+      if (n == 1)
+        p = Draw_CachePic ("gfx/box_mm2.lmp");
+      M_DrawTransPic (cx, cy, p);
+    }
+    p = Draw_CachePic ("gfx/box_bm.lmp");
+    M_DrawTransPic (cx, cy+8, p);
+    width -= 2;
+    cx += 16;
+  }
+
+  // draw right side
+  cy = y;
+  p = Draw_CachePic ("gfx/box_tr.lmp");
+  M_DrawTransPic (cx, cy, p);
+  p = Draw_CachePic ("gfx/box_mr.lmp");
+  for (n = 0; n < lines; n++)
+  {
+    cy += 8;
+    M_DrawTransPic (cx, cy, p);
+  }
+  p = Draw_CachePic ("gfx/box_br.lmp");
+  M_DrawTransPic (cx, cy+8, p);
+}
+
+//=============================================================================
+
+int m_save_demonum;
+
+/*
+================
+M_ToggleMenu_f
+================
+*/
+void M_ToggleMenu_f (void)
+{
+  m_entersound = true;
+
+  if (key_dest == key_menu)
+  {
+    if (m_state != m_main)
+    {
+      M_Menu_Main_f ();
+      return;
+    }
+    key_dest = key_game;
+    m_state = m_none;
+    return;
+  }
+  if (key_dest == key_console)
+  {
+    Con_ToggleConsole_f ();
+  }
+  else
+  {
+    M_Menu_Main_f ();
+  }
+}
+
+
+//=============================================================================
+/* MAIN MENU */
+
+int	m_main_cursor;
+#define	MAIN_ITEMS	5
+
+
+void M_Menu_Main_f (void)
+{
+  if (key_dest != key_menu)
+  {
+    m_save_demonum = cls.demonum;
+    cls.demonum = -1;
+  }
+  key_dest = key_menu;
+  m_state = m_main;
+  m_entersound = true;
+}
+
+
+void M_Main_Draw (void)
+{
+  int		f;
+  qpic_t	*p;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/ttl_main.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+  M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") );
+
+  f = (int)(host_time * 10)%6;
+
+  M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
+}
+
+
+void M_Main_Key (int key)
+{
+  switch (key)
+  {
+  case K_ESCAPE:
+    key_dest = key_game;
+    m_state = m_none;
+    cls.demonum = m_save_demonum;
+    if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected)
+      CL_NextDemo ();
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (++m_main_cursor >= MAIN_ITEMS)
+      m_main_cursor = 0;
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (--m_main_cursor < 0)
+      m_main_cursor = MAIN_ITEMS - 1;
+    break;
+
+  case K_ENTER:
+    m_entersound = true;
+
+    switch (m_main_cursor)
+    {
+    case 0:
+      M_Menu_SinglePlayer_f ();
+      break;
+
+    case 1:
+      M_Menu_MultiPlayer_f ();
+      break;
+
+    case 2:
+      M_Menu_Options_f ();
+      break;
+
+    case 3:
+      M_Menu_Help_f ();
+      break;
+
+    case 4:
+      M_Menu_Quit_f ();
+      break;
+    }
+  }
+}
+
+//=============================================================================
+/* SINGLE PLAYER MENU */
+
+int	m_singleplayer_cursor;
+#define	SINGLEPLAYER_ITEMS	3
+
+
+void M_Menu_SinglePlayer_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_singleplayer;
+  m_entersound = true;
+}
+
+
+void M_SinglePlayer_Draw (void)
+{
+  int		f;
+  qpic_t	*p;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/ttl_sgl.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+  M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") );
+
+  f = (int)(host_time * 10)%6;
+
+  M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
+}
+
+
+void M_SinglePlayer_Key (int key)
+{
+  switch (key)
+  {
+  case K_ESCAPE:
+    M_Menu_Main_f ();
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
+      m_singleplayer_cursor = 0;
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (--m_singleplayer_cursor < 0)
+      m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;
+    break;
+
+  case K_ENTER:
+    m_entersound = true;
+
+    switch (m_singleplayer_cursor)
+    {
+    case 0:
+      if (sv.active)
+        if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n"))
+          break;
+      key_dest = key_game;
+      if (sv.active)
+        Cbuf_AddText ("disconnect\n");
+      Cbuf_AddText ("maxplayers 1\n");
+      Cbuf_AddText ("map start\n");
+      break;
+
+    case 1:
+      M_Menu_Load_f ();
+      break;
+
+    case 2:
+      M_Menu_Save_f ();
+      break;
+    }
+  }
+}
+
+//=============================================================================
+/* LOAD/SAVE MENU */
+
+int		load_cursor;		// 0 < load_cursor < MAX_SAVEGAMES
+
+#define	MAX_SAVEGAMES		12
+char	m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
+int		loadable[MAX_SAVEGAMES];
+
+void M_ScanSaves (void)
+{
+  int		i, j;
+  char	name[MAX_OSPATH];
+  FILE	*f;
+  int		version;
+
+  for (i=0 ; i<MAX_SAVEGAMES ; i++)
+  {
+    strcpy (m_filenames[i], "--- UNUSED SLOT ---");
+    loadable[i] = false;
+    sprintf (name, "%s/s%i.sav", com_gamedir, i);
+    f = fopen (name, "r");
+    if (!f)
+      continue;
+    fscanf (f, "%i\n", &version);
+    fscanf (f, "%79s\n", name);
+    strncpy (m_filenames[i], name, sizeof(m_filenames[i])-1);
+
+  // change _ back to space
+    for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
+      if (m_filenames[i][j] == '_')
+        m_filenames[i][j] = ' ';
+    loadable[i] = true;
+    fclose (f);
+  }
+}
+
+void M_Menu_Load_f (void)
+{
+  m_entersound = true;
+  m_state = m_load;
+  key_dest = key_menu;
+  M_ScanSaves ();
+}
+
+
+void M_Menu_Save_f (void)
+{
+  if (!sv.active)
+    return;
+  if (cl.intermission)
+    return;
+  if (svs.maxclients != 1)
+    return;
+  m_entersound = true;
+  m_state = m_save;
+  key_dest = key_menu;
+  M_ScanSaves ();
+}
+
+
+void M_Load_Draw (void)
+{
+  int		i;
+  qpic_t	*p;
+
+  p = Draw_CachePic ("gfx/p_load.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+
+  for (i=0 ; i< MAX_SAVEGAMES; i++)
+    M_Print (16, 32 + 8*i, m_filenames[i]);
+
+// line cursor
+  M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
+}
+
+
+void M_Save_Draw (void)
+{
+  int		i;
+  qpic_t	*p;
+
+  p = Draw_CachePic ("gfx/p_save.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+
+  for (i=0 ; i<MAX_SAVEGAMES ; i++)
+    M_Print (16, 32 + 8*i, m_filenames[i]);
+
+// line cursor
+  M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
+}
+
+
+void M_Load_Key (int k)
+{
+  switch (k)
+  {
+  case K_ESCAPE:
+    M_Menu_SinglePlayer_f ();
+    break;
+
+  case K_ENTER:
+    S_LocalSound ("misc/menu2.wav");
+    if (!loadable[load_cursor])
+      return;
+    m_state = m_none;
+    key_dest = key_game;
+
+  // Host_Loadgame_f can't bring up the loading plaque because too much
+  // stack space has been used, so do it now
+    SCR_BeginLoadingPlaque ();
+
+  // issue the load command
+    Cbuf_AddText (va ("load s%i\n", load_cursor) );
+    return;
+
+  case K_UPARROW:
+  case K_LEFTARROW:
+    S_LocalSound ("misc/menu1.wav");
+    load_cursor--;
+    if (load_cursor < 0)
+      load_cursor = MAX_SAVEGAMES-1;
+    break;
+
+  case K_DOWNARROW:
+  case K_RIGHTARROW:
+    S_LocalSound ("misc/menu1.wav");
+    load_cursor++;
+    if (load_cursor >= MAX_SAVEGAMES)
+      load_cursor = 0;
+    break;
+  }
+}
+
+
+void M_Save_Key (int k)
+{
+  switch (k)
+  {
+  case K_ESCAPE:
+    M_Menu_SinglePlayer_f ();
+    break;
+
+  case K_ENTER:
+    m_state = m_none;
+    key_dest = key_game;
+    Cbuf_AddText (va("save s%i\n", load_cursor));
+    return;
+
+  case K_UPARROW:
+  case K_LEFTARROW:
+    S_LocalSound ("misc/menu1.wav");
+    load_cursor--;
+    if (load_cursor < 0)
+      load_cursor = MAX_SAVEGAMES-1;
+    break;
+
+  case K_DOWNARROW:
+  case K_RIGHTARROW:
+    S_LocalSound ("misc/menu1.wav");
+    load_cursor++;
+    if (load_cursor >= MAX_SAVEGAMES)
+      load_cursor = 0;
+    break;
+  }
+}
+
+//=============================================================================
+/* MULTIPLAYER MENU */
+
+int	m_multiplayer_cursor;
+#define	MULTIPLAYER_ITEMS	3
+
+
+void M_Menu_MultiPlayer_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_multiplayer;
+  m_entersound = true;
+}
+
+
+void M_MultiPlayer_Draw (void)
+{
+  int		f;
+  qpic_t	*p;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+  M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") );
+
+  f = (int)(host_time * 10)%6;
+
+  M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
+
+  if (serialAvailable || ipxAvailable || tcpipAvailable)
+    return;
+  M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
+}
+
+
+void M_MultiPlayer_Key (int key)
+{
+  switch (key)
+  {
+  case K_ESCAPE:
+    M_Menu_Main_f ();
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
+      m_multiplayer_cursor = 0;
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (--m_multiplayer_cursor < 0)
+      m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;
+    break;
+
+  case K_ENTER:
+    m_entersound = true;
+    switch (m_multiplayer_cursor)
+    {
+    case 0:
+      if (serialAvailable || ipxAvailable || tcpipAvailable)
+        M_Menu_Net_f ();
+      break;
+
+    case 1:
+      if (serialAvailable || ipxAvailable || tcpipAvailable)
+        M_Menu_Net_f ();
+      break;
+
+    case 2:
+      M_Menu_Setup_f ();
+      break;
+    }
+  }
+}
+
+//=============================================================================
+/* SETUP MENU */
+
+int		setup_cursor = 4;
+int		setup_cursor_table[] = {40, 56, 80, 104, 140};
+
+char	setup_hostname[16];
+char	setup_myname[16];
+int		setup_oldtop;
+int		setup_oldbottom;
+int		setup_top;
+int		setup_bottom;
+
+#define	NUM_SETUP_CMDS	5
+
+void M_Menu_Setup_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_setup;
+  m_entersound = true;
+  Q_strcpy(setup_myname, cl_name.string);
+  Q_strcpy(setup_hostname, hostname.string);
+  setup_top = setup_oldtop = ((int)cl_color.value) >> 4;
+  setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;
+}
+
+
+void M_Setup_Draw (void)
+{
+  qpic_t	*p;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+
+  M_Print (64, 40, "Hostname");
+  M_DrawTextBox (160, 32, 16, 1);
+  M_Print (168, 40, setup_hostname);
+
+  M_Print (64, 56, "Your name");
+  M_DrawTextBox (160, 48, 16, 1);
+  M_Print (168, 56, setup_myname);
+
+  M_Print (64, 80, "Shirt color");
+  M_Print (64, 104, "Pants color");
+
+  M_DrawTextBox (64, 140-8, 14, 1);
+  M_Print (72, 140, "Accept Changes");
+
+  p = Draw_CachePic ("gfx/bigbox.lmp");
+  M_DrawTransPic (160, 64, p);
+  p = Draw_CachePic ("gfx/menuplyr.lmp");
+  M_BuildTranslationTable(setup_top*16, setup_bottom*16);
+  M_DrawTransPicTranslate (172, 72, p);
+
+  M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));
+
+  if (setup_cursor == 0)
+    M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
+
+  if (setup_cursor == 1)
+    M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
+}
+
+
+void M_Setup_Key (int k)
+{
+  int			l;
+
+  switch (k)
+  {
+  case K_ESCAPE:
+    M_Menu_MultiPlayer_f ();
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    setup_cursor--;
+    if (setup_cursor < 0)
+      setup_cursor = NUM_SETUP_CMDS-1;
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    setup_cursor++;
+    if (setup_cursor >= NUM_SETUP_CMDS)
+      setup_cursor = 0;
+    break;
+
+  case K_LEFTARROW:
+    if (setup_cursor < 2)
+      return;
+    S_LocalSound ("misc/menu3.wav");
+    if (setup_cursor == 2)
+      setup_top = setup_top - 1;
+    if (setup_cursor == 3)
+      setup_bottom = setup_bottom - 1;
+    break;
+  case K_RIGHTARROW:
+    if (setup_cursor < 2)
+      return;
+forward:
+    S_LocalSound ("misc/menu3.wav");
+    if (setup_cursor == 2)
+      setup_top = setup_top + 1;
+    if (setup_cursor == 3)
+      setup_bottom = setup_bottom + 1;
+    break;
+
+  case K_ENTER:
+    if (setup_cursor == 0 || setup_cursor == 1)
+      return;
+
+    if (setup_cursor == 2 || setup_cursor == 3)
+      goto forward;
+
+    // setup_cursor == 4 (OK)
+    if (Q_strcmp(cl_name.string, setup_myname) != 0)
+      Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
+    if (Q_strcmp(hostname.string, setup_hostname) != 0)
+      Cvar_Set("hostname", setup_hostname);
+    if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
+      Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) );
+    m_entersound = true;
+    M_Menu_MultiPlayer_f ();
+    break;
+
+  case K_BACKSPACE:
+    if (setup_cursor == 0)
+    {
+      if (strlen(setup_hostname))
+        setup_hostname[strlen(setup_hostname)-1] = 0;
+    }
+
+    if (setup_cursor == 1)
+    {
+      if (strlen(setup_myname))
+        setup_myname[strlen(setup_myname)-1] = 0;
+    }
+    break;
+
+  default:
+    if (k < 32 || k > 127)
+      break;
+    if (setup_cursor == 0)
+    {
+      l = strlen(setup_hostname);
+      if (l < 15)
+      {
+        setup_hostname[l+1] = 0;
+        setup_hostname[l] = k;
+      }
+    }
+    if (setup_cursor == 1)
+    {
+      l = strlen(setup_myname);
+      if (l < 15)
+      {
+        setup_myname[l+1] = 0;
+        setup_myname[l] = k;
+      }
+    }
+  }
+
+  if (setup_top > 13)
+    setup_top = 0;
+  if (setup_top < 0)
+    setup_top = 13;
+  if (setup_bottom > 13)
+    setup_bottom = 0;
+  if (setup_bottom < 0)
+    setup_bottom = 13;
+}
+
+//=============================================================================
+/* NET MENU */
+
+int	m_net_cursor;
+int m_net_items;
+int m_net_saveHeight;
+
+const char *net_helpMessage [] =
+{
+/* .........1.........2.... */
+  "                        ",
+  " Two computers connected",
+  "   through two modems.  ",
+  "                        ",
+
+  "                        ",
+  " Two computers connected",
+  " by a null-modem cable. ",
+  "                        ",
+
+  " Novell network LANs    ",
+  " or Windows 95 DOS-box. ",
+  "                        ",
+  "(LAN=Local Area Network)",
+
+  " Commonly used to play  ",
+  " over the Internet, but ",
+  " also used on a Local   ",
+  " Area Network.          "
+};
+
+void M_Menu_Net_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_net;
+  m_entersound = true;
+  m_net_items = 4;
+
+  if (m_net_cursor >= m_net_items)
+    m_net_cursor = 0;
+  m_net_cursor--;
+  M_Net_Key (K_DOWNARROW);
+}
+
+
+void M_Net_Draw (void)
+{
+  int		f;
+  qpic_t	*p;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+
+  f = 32;
+
+  if (serialAvailable)
+  {
+    p = Draw_CachePic ("gfx/netmen1.lmp");
+  }
+  else
+  {
+#ifdef _WIN32
+    p = NULL;
+#else
+    p = Draw_CachePic ("gfx/dim_modm.lmp");
+#endif
+  }
+
+  if (p)
+    M_DrawTransPic (72, f, p);
+
+  f += 19;
+
+  if (serialAvailable)
+  {
+    p = Draw_CachePic ("gfx/netmen2.lmp");
+  }
+  else
+  {
+#ifdef _WIN32
+    p = NULL;
+#else
+    p = Draw_CachePic ("gfx/dim_drct.lmp");
+#endif
+  }
+
+  if (p)
+    M_DrawTransPic (72, f, p);
+
+  f += 19;
+  if (ipxAvailable)
+    p = Draw_CachePic ("gfx/netmen3.lmp");
+  else
+    p = Draw_CachePic ("gfx/dim_ipx.lmp");
+  M_DrawTransPic (72, f, p);
+
+  f += 19;
+  if (tcpipAvailable)
+    p = Draw_CachePic ("gfx/netmen4.lmp");
+  else
+    p = Draw_CachePic ("gfx/dim_tcp.lmp");
+  M_DrawTransPic (72, f, p);
+
+  if (m_net_items == 5)	// JDC, could just be removed
+  {
+    f += 19;
+    p = Draw_CachePic ("gfx/netmen5.lmp");
+    M_DrawTransPic (72, f, p);
+  }
+
+  f = (320-26*8)/2;
+  M_DrawTextBox (f, 134, 24, 4);
+  f += 8;
+  M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]);
+  M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]);
+  M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]);
+  M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]);
+
+  f = (int)(host_time * 10)%6;
+  M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
+}
+
+
+void M_Net_Key (int k)
+{
+again:
+  switch (k)
+  {
+  case K_ESCAPE:
+    M_Menu_MultiPlayer_f ();
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (++m_net_cursor >= m_net_items)
+      m_net_cursor = 0;
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    if (--m_net_cursor < 0)
+      m_net_cursor = m_net_items - 1;
+    break;
+
+  case K_ENTER:
+    m_entersound = true;
+
+    switch (m_net_cursor)
+    {
+    case 0:
+      M_Menu_SerialConfig_f ();
+      break;
+
+    case 1:
+      M_Menu_SerialConfig_f ();
+      break;
+
+    case 2:
+      M_Menu_LanConfig_f ();
+      break;
+
+    case 3:
+      M_Menu_LanConfig_f ();
+      break;
+
+    case 4:
+// multiprotocol
+      break;
+    }
+  }
+
+  if (m_net_cursor == 0 && !serialAvailable)
+    goto again;
+  if (m_net_cursor == 1 && !serialAvailable)
+    goto again;
+  if (m_net_cursor == 2 && !ipxAvailable)
+    goto again;
+  if (m_net_cursor == 3 && !tcpipAvailable)
+    goto again;
+}
+
+//=============================================================================
+/* OPTIONS MENU */
+
+#ifdef _WIN32
+#define	OPTIONS_ITEMS	14
+#else
+#define	OPTIONS_ITEMS	13
+#endif
+
+#define	SLIDER_RANGE	10
+
+int		options_cursor;
+
+void M_Menu_Options_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_options;
+  m_entersound = true;
+
+#ifdef _WIN32
+  if ((options_cursor == 13) && (modestate != MS_WINDOWED))
+  {
+    options_cursor = 0;
+  }
+#endif
+}
+
+
+void M_AdjustSliders (int dir)
+{
+  S_LocalSound ("misc/menu3.wav");
+
+  switch (options_cursor)
+  {
+  case 3:	// screen size
+    scr_viewsize.value += dir * 10;
+    if (scr_viewsize.value < 30)
+      scr_viewsize.value = 30;
+    if (scr_viewsize.value > 120)
+      scr_viewsize.value = 120;
+    Cvar_SetValue ("viewsize", scr_viewsize.value);
+    break;
+  case 4:	// gamma
+    v_gamma.value -= dir * 0.05;
+    if (v_gamma.value < 0.5)
+      v_gamma.value = 0.5;
+    if (v_gamma.value > 1)
+      v_gamma.value = 1;
+    Cvar_SetValue ("gamma", v_gamma.value);
+    break;
+  case 5:	// mouse speed
+    sensitivity.value += dir * 0.5;
+    if (sensitivity.value < 1)
+      sensitivity.value = 1;
+    if (sensitivity.value > 11)
+      sensitivity.value = 11;
+    Cvar_SetValue ("sensitivity", sensitivity.value);
+    break;
+  case 6:	// music volume
+#ifdef _WIN32
+    bgmvolume.value += dir * 1.0;
+#else
+    bgmvolume.value += dir * 0.1;
+#endif
+    if (bgmvolume.value < 0)
+      bgmvolume.value = 0;
+    if (bgmvolume.value > 1)
+      bgmvolume.value = 1;
+    Cvar_SetValue ("bgmvolume", bgmvolume.value);
+    break;
+  case 7:	// sfx volume
+    volume.value += dir * 0.1;
+    if (volume.value < 0)
+      volume.value = 0;
+    if (volume.value > 1)
+      volume.value = 1;
+    Cvar_SetValue ("volume", volume.value);
+    break;
+
+  case 8:	// allways run
+    if (cl_forwardspeed.value > 200)
+    {
+      Cvar_SetValue ("cl_forwardspeed", 200);
+      Cvar_SetValue ("cl_backspeed", 200);
+    }
+    else
+    {
+      Cvar_SetValue ("cl_forwardspeed", 400);
+      Cvar_SetValue ("cl_backspeed", 400);
+    }
+    break;
+
+  case 9:	// invert mouse
+    Cvar_SetValue ("m_pitch", -m_pitch.value);
+    break;
+
+  case 10:	// lookspring
+    Cvar_SetValue ("lookspring", !lookspring.value);
+    break;
+
+  case 11:	// lookstrafe
+    Cvar_SetValue ("lookstrafe", !lookstrafe.value);
+    break;
+
+#ifdef _WIN32
+  case 13:	// _windowed_mouse
+    Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value);
+    break;
+#endif
+  }
+}
+
+
+void M_DrawSlider (int x, int y, float range)
+{
+  int	i;
+
+  if (range < 0)
+    range = 0;
+  if (range > 1)
+    range = 1;
+  M_DrawCharacter (x-8, y, 128);
+  for (i=0 ; i<SLIDER_RANGE ; i++)
+    M_DrawCharacter (x + i*8, y, 129);
+  M_DrawCharacter (x+i*8, y, 130);
+  M_DrawCharacter ((int) (x + (SLIDER_RANGE-1)*8 * range), y, 131);
+}
+
+void M_DrawCheckbox (int x, int y, int on)
+{
+#if 0
+  if (on)
+    M_DrawCharacter (x, y, 131);
+  else
+    M_DrawCharacter (x, y, 129);
+#endif
+  if (on)
+    M_Print (x, y, "on");
+  else
+    M_Print (x, y, "off");
+}
+
+void M_Options_Draw (void)
+{
+  float		r;
+  qpic_t	*p;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_option.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+
+  M_Print (16, 32, "    Customize controls");
+  M_Print (16, 40, "         Go to console");
+  M_Print (16, 48, "     Reset to defaults");
+
+  M_Print (16, 56, "           Screen size");
+  r = (scr_viewsize.value - 30) / (120 - 30);
+  M_DrawSlider (220, 56, r);
+
+  M_Print (16, 64, "            Brightness");
+  r = (1.0 - v_gamma.value) / 0.5;
+  M_DrawSlider (220, 64, r);
+
+  M_Print (16, 72, "           Mouse Speed");
+  r = (sensitivity.value - 1)/10;
+  M_DrawSlider (220, 72, r);
+
+  M_Print (16, 80, "       CD Music Volume");
+  r = bgmvolume.value;
+  M_DrawSlider (220, 80, r);
+
+  M_Print (16, 88, "          Sound Volume");
+  r = volume.value;
+  M_DrawSlider (220, 88, r);
+
+  M_Print (16, 96,  "            Always Run");
+  M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200);
+
+  M_Print (16, 104, "          Invert Mouse");
+  M_DrawCheckbox (220, 104, m_pitch.value < 0);
+
+  M_Print (16, 112, "            Lookspring");
+  M_DrawCheckbox (220, 112, (int) lookspring.value);
+
+  M_Print (16, 120, "            Lookstrafe");
+  M_DrawCheckbox (220, 120, (int) lookstrafe.value);
+
+  if (vid_menudrawfn)
+    M_Print (16, 128, "         Video Options");
+
+#ifdef _WIN32
+  if (modestate == MS_WINDOWED)
+  {
+    M_Print (16, 136, "             Use Mouse");
+    M_DrawCheckbox (220, 136, _windowed_mouse.value);
+  }
+#endif
+
+// cursor
+  M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));
+}
+
+
+void M_Options_Key (int k)
+{
+  switch (k)
+  {
+  case K_ESCAPE:
+    M_Menu_Main_f ();
+    break;
+
+  case K_ENTER:
+    m_entersound = true;
+    switch (options_cursor)
+    {
+    case 0:
+      M_Menu_Keys_f ();
+      break;
+    case 1:
+      m_state = m_none;
+      Con_ToggleConsole_f ();
+      break;
+    case 2:
+      Cbuf_AddText ("exec default.cfg\n");
+      break;
+    case 12:
+      M_Menu_Video_f ();
+      break;
+    default:
+      M_AdjustSliders (1);
+      break;
+    }
+    return;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    options_cursor--;
+    if (options_cursor < 0)
+      options_cursor = OPTIONS_ITEMS-1;
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    options_cursor++;
+    if (options_cursor >= OPTIONS_ITEMS)
+      options_cursor = 0;
+    break;
+
+  case K_LEFTARROW:
+    M_AdjustSliders (-1);
+    break;
+
+  case K_RIGHTARROW:
+    M_AdjustSliders (1);
+    break;
+  }
+
+  if (options_cursor == 12 && vid_menudrawfn == NULL)
+  {
+    if (k == K_UPARROW)
+      options_cursor = 11;
+    else
+      options_cursor = 0;
+  }
+
+#ifdef _WIN32
+  if ((options_cursor == 13) && (modestate != MS_WINDOWED))
+  {
+    if (k == K_UPARROW)
+      options_cursor = 12;
+    else
+      options_cursor = 0;
+  }
+#endif
+}
+
+//=============================================================================
+/* KEYS MENU */
+
+const char *bindnames[][2] =
+{
+{"+attack", 		"attack"},
+{"impulse 10", 		"change weapon"},
+{"+jump", 			"jump / swim up"},
+{"+forward", 		"walk forward"},
+{"+back", 			"backpedal"},
+{"+left", 			"turn left"},
+{"+right", 			"turn right"},
+{"+speed", 			"run"},
+{"+moveleft", 		"step left"},
+{"+moveright", 		"step right"},
+{"+strafe", 		"sidestep"},
+{"+lookup", 		"look up"},
+{"+lookdown", 		"look down"},
+{"centerview", 		"center view"},
+{"+mlook", 			"mouse look"},
+{"+klook", 			"keyboard look"},
+{"+moveup",			"swim up"},
+{"+movedown",		"swim down"}
+};
+
+#define	NUMCOMMANDS	(sizeof(bindnames)/sizeof(bindnames[0]))
+
+int		keys_cursor;
+int		bind_grab;
+
+void M_Menu_Keys_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_keys;
+  m_entersound = true;
+}
+
+
+void M_FindKeysForCommand (const char *command, int *twokeys)
+{
+  int		count;
+  int		j;
+  int		l;
+  char	*b;
+
+  twokeys[0] = twokeys[1] = -1;
+  l = strlen(command);
+  count = 0;
+
+  for (j=0 ; j<256 ; j++)
+  {
+    b = keybindings[j];
+    if (!b)
+      continue;
+    if (!strncmp (b, command, l) )
+    {
+      twokeys[count] = j;
+      count++;
+      if (count == 2)
+        break;
+    }
+  }
+}
+
+void M_UnbindCommand (const char *command)
+{
+  int		j;
+  int		l;
+  char	*b;
+
+  l = strlen(command);
+
+  for (j=0 ; j<256 ; j++)
+  {
+    b = keybindings[j];
+    if (!b)
+      continue;
+    if (!strncmp (b, command, l) )
+      Key_SetBinding (j, "");
+  }
+}
+
+
+void M_Keys_Draw (void)
+{
+  int		i, l;
+  int		keys[2];
+  const char	*name;
+  int		x, y;
+  qpic_t	*p;
+
+  p = Draw_CachePic ("gfx/ttl_cstm.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+
+  if (bind_grab)
+    M_Print (12, 32, "Press a key or button for this action");
+  else
+    M_Print (18, 32, "Enter to change, backspace to clear");
+
+// search for known bindings
+  for (i=0 ; i< (int) (NUMCOMMANDS) ; i++)
+  {
+    y = 48 + 8*i;
+
+    M_Print (16, y, bindnames[i][1]);
+
+    l = strlen (bindnames[i][0]);
+
+    M_FindKeysForCommand (bindnames[i][0], keys);
+
+    if (keys[0] == -1)
+    {
+      M_Print (140, y, "???");
+    }
+    else
+    {
+      name = Key_KeynumToString (keys[0]);
+      M_Print (140, y, name);
+      x = strlen(name) * 8;
+      if (keys[1] != -1)
+      {
+        M_Print (140 + x + 8, y, "or");
+        M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
+      }
+    }
+  }
+
+  if (bind_grab)
+    M_DrawCharacter (130, 48 + keys_cursor*8, '=');
+  else
+    M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
+}
+
+
+void M_Keys_Key (int k)
+{
+  char	cmd[80];
+  int		keys[2];
+
+  if (bind_grab)
+  {	// defining a key
+    S_LocalSound ("misc/menu1.wav");
+    if (k == K_ESCAPE)
+    {
+      bind_grab = false;
+    }
+    else if (k != '`')
+    {
+      sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
+      Cbuf_InsertText (cmd);
+    }
+
+    bind_grab = false;
+    return;
+  }
+
+  switch (k)
+  {
+  case K_ESCAPE:
+    M_Menu_Options_f ();
+    break;
+
+  case K_LEFTARROW:
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    keys_cursor--;
+    if (keys_cursor < 0)
+      keys_cursor = NUMCOMMANDS-1;
+    break;
+
+  case K_DOWNARROW:
+  case K_RIGHTARROW:
+    S_LocalSound ("misc/menu1.wav");
+    keys_cursor++;
+    if (keys_cursor >= (int)(NUMCOMMANDS))
+      keys_cursor = 0;
+    break;
+
+  case K_ENTER:		// go into bind mode
+    M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
+    S_LocalSound ("misc/menu2.wav");
+    if (keys[1] != -1)
+      M_UnbindCommand (bindnames[keys_cursor][0]);
+    bind_grab = true;
+    break;
+
+  case K_BACKSPACE:		// delete bindings
+  case K_DEL:				// delete bindings
+    S_LocalSound ("misc/menu2.wav");
+    M_UnbindCommand (bindnames[keys_cursor][0]);
+    break;
+  }
+}
+
+//=============================================================================
+/* VIDEO MENU */
+
+void M_Menu_Video_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_video;
+  m_entersound = true;
+}
+
+
+void M_Video_Draw (void)
+{
+  (*vid_menudrawfn) ();
+}
+
+
+void M_Video_Key (int key)
+{
+  (*vid_menukeyfn) (key);
+}
+
+//=============================================================================
+/* HELP MENU */
+
+int		help_page;
+#define	NUM_HELP_PAGES	6
+
+
+void M_Menu_Help_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_help;
+  m_entersound = true;
+  help_page = 0;
+}
+
+
+
+void M_Help_Draw (void)
+{
+  M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
+}
+
+
+void M_Help_Key (int key)
+{
+  switch (key)
+  {
+  case K_ESCAPE:
+    M_Menu_Main_f ();
+    break;
+
+  case K_UPARROW:
+  case K_RIGHTARROW:
+    m_entersound = true;
+    if (++help_page >= NUM_HELP_PAGES)
+      help_page = 0;
+    break;
+
+  case K_DOWNARROW:
+  case K_LEFTARROW:
+    m_entersound = true;
+    if (--help_page < 0)
+      help_page = NUM_HELP_PAGES-1;
+    break;
+  }
+
+}
+
+//=============================================================================
+/* QUIT MENU */
+
+int		msgNumber;
+int		m_quit_prevstate;
+qboolean	wasInMenus;
+
+#ifndef	_WIN32
+const char *quitMessage [] =
+{
+/* .........1.........2.... */
+  "  Are you gonna quit    ",
+  "  this game just like   ",
+  "   everything else?     ",
+  "                        ",
+
+  " Milord, methinks that  ",
+  "   thou art a lowly     ",
+  " quitter. Is this true? ",
+  "                        ",
+
+  " Do I need to bust your ",
+  "  face open for trying  ",
+  "        to quit?        ",
+  "                        ",
+
+  " Man, I oughta smack you",
+  "   for trying to quit!  ",
+  "     Press Y to get     ",
+  "      smacked out.      ",
+
+  " Press Y to quit like a ",
+  "   big loser in life.   ",
+  "  Press N to stay proud ",
+  "    and successful!     ",
+
+  "   If you press Y to    ",
+  "  quit, I will summon   ",
+  "  Satan all over your   ",
+  "      hard drive!       ",
+
+  "  Um, Asmodeus dislikes ",
+  " his children trying to ",
+  " quit. Press Y to return",
+  "   to your Tinkertoys.  ",
+
+  "  If you quit now, I'll ",
+  "  throw a blanket-party ",
+  "   for you next time!   ",
+  "                        "
+};
+#endif
+
+void M_Menu_Quit_f (void)
+{
+  if (m_state == m_quit)
+    return;
+  wasInMenus = (key_dest == key_menu);
+  key_dest = key_menu;
+  m_quit_prevstate = m_state;
+  m_state = m_quit;
+  m_entersound = true;
+  msgNumber = rand()&7;
+}
+
+
+void M_Quit_Key (int key)
+{
+  switch (key)
+  {
+  case K_ESCAPE:
+  case 'n':
+  case 'N':
+    if (wasInMenus)
+    {
+      m_state = (m_state_t) m_quit_prevstate;
+      m_entersound = true;
+    }
+    else
+    {
+      key_dest = key_game;
+      m_state = (m_state_t) m_none;
+    }
+    break;
+
+  case 'Y':
+  case 'y':
+  case K_ENTER:
+    key_dest = key_console;
+    Host_Quit_f ();
+    break;
+
+  default:
+    break;
+  }
+
+}
+
+
+void M_Quit_Draw (void)
+{
+  if (wasInMenus)
+  {
+    m_state = (m_state_t) m_quit_prevstate;
+    m_recursiveDraw = true;
+    M_Draw ();
+    m_state = m_quit;
+  }
+
+#ifdef _WIN32
+  M_DrawTextBox (0, 0, 38, 23);
+  M_PrintWhite (16, 12,  "  Quake version 1.09 by id Software\n\n");
+  M_PrintWhite (16, 28,  "Programming        Art \n");
+  M_Print (16, 36,  " John Carmack       Adrian Carmack\n");
+  M_Print (16, 44,  " Michael Abrash     Kevin Cloud\n");
+  M_Print (16, 52,  " John Cash          Paul Steed\n");
+  M_Print (16, 60,  " Dave 'Zoid' Kirsch\n");
+  M_PrintWhite (16, 68,  "Design             Biz\n");
+  M_Print (16, 76,  " John Romero        Jay Wilbur\n");
+  M_Print (16, 84,  " Sandy Petersen     Mike Wilson\n");
+  M_Print (16, 92,  " American McGee     Donna Jackson\n");
+  M_Print (16, 100,  " Tim Willits        Todd Hollenshead\n");
+  M_PrintWhite (16, 108, "Support            Projects\n");
+  M_Print (16, 116, " Barrett Alexander  Shawn Green\n");
+  M_PrintWhite (16, 124, "Sound Effects\n");
+  M_Print (16, 132, " Trent Reznor and Nine Inch Nails\n\n");
+  M_PrintWhite (16, 140, "Quake is a trademark of Id Software,\n");
+  M_PrintWhite (16, 148, "inc., (c)1996 Id Software, inc. All\n");
+  M_PrintWhite (16, 156, "rights reserved. NIN logo is a\n");
+  M_PrintWhite (16, 164, "registered trademark licensed to\n");
+  M_PrintWhite (16, 172, "Nothing Interactive, Inc. All rights\n");
+  M_PrintWhite (16, 180, "reserved. Press y to exit\n");
+#else
+  M_DrawTextBox (56, 76, 24, 4);
+#if 0
+  M_Print (64, 84,  quitMessage[msgNumber*4+0]);
+  M_Print (64, 92,  quitMessage[msgNumber*4+1]);
+  M_Print (64, 100, quitMessage[msgNumber*4+2]);
+  M_Print (64, 108, quitMessage[msgNumber*4+3]);
+#else
+  M_PrintWhite(64, 92, "Click Trackball to Quit");
+#endif
+#endif
+}
+
+//=============================================================================
+
+/* SERIAL CONFIG MENU */
+
+int		serialConfig_cursor;
+int		serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
+#define	NUM_SERIALCONFIG_CMDS	6
+
+static int ISA_uarts[]	= {0x3f8,0x2f8,0x3e8,0x2e8};
+static int ISA_IRQs[]	= {4,3,4,3};
+int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
+
+int		serialConfig_comport;
+int		serialConfig_irq ;
+int		serialConfig_baud;
+char	serialConfig_phone[16];
+
+void M_Menu_SerialConfig_f (void)
+{
+  int		n;
+  int		port;
+  int		baudrate;
+  qboolean	useModem;
+
+  key_dest = key_menu;
+  m_state = m_serialconfig;
+  m_entersound = true;
+  if (JoiningGame && SerialConfig)
+    serialConfig_cursor = 4;
+  else
+    serialConfig_cursor = 5;
+
+  (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
+
+  // map uart's port to COMx
+  for (n = 0; n < 4; n++)
+    if (ISA_uarts[n] == port)
+      break;
+  if (n == 4)
+  {
+    n = 0;
+    serialConfig_irq = 4;
+  }
+  serialConfig_comport = n + 1;
+
+  // map baudrate to index
+  for (n = 0; n < 6; n++)
+    if (serialConfig_baudrate[n] == baudrate)
+      break;
+  if (n == 6)
+    n = 5;
+  serialConfig_baud = n;
+
+  m_return_onerror = false;
+  m_return_reason[0] = 0;
+}
+
+
+void M_SerialConfig_Draw (void)
+{
+  qpic_t	*p;
+  int		basex;
+  const char	*startJoin;
+  const char	*directModem;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  basex = (320-p->width)/2;
+  M_DrawPic (basex, 4, p);
+
+  if (StartingGame)
+    startJoin = "New Game";
+  else
+    startJoin = "Join Game";
+  if (SerialConfig)
+    directModem = "Modem";
+  else
+    directModem = "Direct Connect";
+  M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
+  basex += 8;
+
+  M_Print (basex, serialConfig_cursor_table[0], "Port");
+  M_DrawTextBox (160, 40, 4, 1);
+  M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport));
+
+  M_Print (basex, serialConfig_cursor_table[1], "IRQ");
+  M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
+  M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq));
+
+  M_Print (basex, serialConfig_cursor_table[2], "Baud");
+  M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
+  M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud]));
+
+  if (SerialConfig)
+  {
+    M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
+    if (JoiningGame)
+    {
+      M_Print (basex, serialConfig_cursor_table[4], "Phone number");
+      M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
+      M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
+    }
+  }
+
+  if (JoiningGame)
+  {
+    M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
+    M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
+  }
+  else
+  {
+    M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
+    M_Print (basex+8, serialConfig_cursor_table[5], "OK");
+  }
+
+  M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
+
+  if (serialConfig_cursor == 4)
+    M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
+
+  if (*m_return_reason)
+    M_PrintWhite (basex, 148, m_return_reason);
+}
+
+
+void M_SerialConfig_Key (int key)
+{
+  int		l;
+
+  switch (key)
+  {
+  case K_ESCAPE:
+    M_Menu_Net_f ();
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    serialConfig_cursor--;
+    if (serialConfig_cursor < 0)
+      serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    serialConfig_cursor++;
+    if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
+      serialConfig_cursor = 0;
+    break;
+
+  case K_LEFTARROW:
+    if (serialConfig_cursor > 2)
+      break;
+    S_LocalSound ("misc/menu3.wav");
+
+    if (serialConfig_cursor == 0)
+    {
+      serialConfig_comport--;
+      if (serialConfig_comport == 0)
+        serialConfig_comport = 4;
+      serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
+    }
+
+    if (serialConfig_cursor == 1)
+    {
+      serialConfig_irq--;
+      if (serialConfig_irq == 6)
+        serialConfig_irq = 5;
+      if (serialConfig_irq == 1)
+        serialConfig_irq = 7;
+    }
+
+    if (serialConfig_cursor == 2)
+    {
+      serialConfig_baud--;
+      if (serialConfig_baud < 0)
+        serialConfig_baud = 5;
+    }
+
+    break;
+
+  case K_RIGHTARROW:
+    if (serialConfig_cursor > 2)
+      break;
+forward:
+    S_LocalSound ("misc/menu3.wav");
+
+    if (serialConfig_cursor == 0)
+    {
+      serialConfig_comport++;
+      if (serialConfig_comport > 4)
+        serialConfig_comport = 1;
+      serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
+    }
+
+    if (serialConfig_cursor == 1)
+    {
+      serialConfig_irq++;
+      if (serialConfig_irq == 6)
+        serialConfig_irq = 7;
+      if (serialConfig_irq == 8)
+        serialConfig_irq = 2;
+    }
+
+    if (serialConfig_cursor == 2)
+    {
+      serialConfig_baud++;
+      if (serialConfig_baud > 5)
+        serialConfig_baud = 0;
+    }
+
+    break;
+
+  case K_ENTER:
+    if (serialConfig_cursor < 3)
+      goto forward;
+
+    m_entersound = true;
+
+    if (serialConfig_cursor == 3)
+    {
+      (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
+
+      M_Menu_ModemConfig_f ();
+      break;
+    }
+
+    if (serialConfig_cursor == 4)
+    {
+      serialConfig_cursor = 5;
+      break;
+    }
+
+    // serialConfig_cursor == 5 (OK/CONNECT)
+    (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
+
+    M_ConfigureNetSubsystem ();
+
+    if (StartingGame)
+    {
+      M_Menu_GameOptions_f ();
+      break;
+    }
+
+    m_return_state = m_state;
+    m_return_onerror = true;
+    key_dest = key_game;
+    m_state = m_none;
+
+    if (SerialConfig)
+      Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
+    else
+      Cbuf_AddText ("connect\n");
+    break;
+
+  case K_BACKSPACE:
+    if (serialConfig_cursor == 4)
+    {
+      if (strlen(serialConfig_phone))
+        serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
+    }
+    break;
+
+  default:
+    if (key < 32 || key > 127)
+      break;
+    if (serialConfig_cursor == 4)
+    {
+      l = strlen(serialConfig_phone);
+      if (l < 15)
+      {
+        serialConfig_phone[l+1] = 0;
+        serialConfig_phone[l] = key;
+      }
+    }
+  }
+
+  if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
+  {
+    if (key == K_UPARROW)
+      serialConfig_cursor = 2;
+    else
+      serialConfig_cursor = 5;
+  }
+  if (SerialConfig && StartingGame && serialConfig_cursor == 4)
+  {
+    if (key == K_UPARROW)
+      serialConfig_cursor = 3;
+    else
+      serialConfig_cursor = 5;
+  }
+}
+
+//=============================================================================
+/* MODEM CONFIG MENU */
+
+int		modemConfig_cursor;
+int		modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
+#define NUM_MODEMCONFIG_CMDS	5
+
+char	modemConfig_dialing;
+char	modemConfig_clear [16];
+char	modemConfig_init [32];
+char	modemConfig_hangup [16];
+
+void M_Menu_ModemConfig_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_modemconfig;
+  m_entersound = true;
+  (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
+}
+
+
+void M_ModemConfig_Draw (void)
+{
+  qpic_t	*p;
+  int		basex;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  basex = (320-p->width)/2;
+  M_DrawPic (basex, 4, p);
+  basex += 8;
+
+  if (modemConfig_dialing == 'P')
+    M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
+  else
+    M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
+
+  M_Print (basex, modemConfig_cursor_table[1], "Clear");
+  M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
+  M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
+  if (modemConfig_cursor == 1)
+    M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
+
+  M_Print (basex, modemConfig_cursor_table[2], "Init");
+  M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
+  M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
+  if (modemConfig_cursor == 2)
+    M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
+
+  M_Print (basex, modemConfig_cursor_table[3], "Hangup");
+  M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
+  M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
+  if (modemConfig_cursor == 3)
+    M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
+
+  M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
+  M_Print (basex+8, modemConfig_cursor_table[4], "OK");
+
+  M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
+}
+
+
+void M_ModemConfig_Key (int key)
+{
+  int		l;
+
+  switch (key)
+  {
+  case K_ESCAPE:
+    M_Menu_SerialConfig_f ();
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    modemConfig_cursor--;
+    if (modemConfig_cursor < 0)
+      modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    modemConfig_cursor++;
+    if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
+      modemConfig_cursor = 0;
+    break;
+
+  case K_LEFTARROW:
+  case K_RIGHTARROW:
+    if (modemConfig_cursor == 0)
+    {
+      if (modemConfig_dialing == 'P')
+        modemConfig_dialing = 'T';
+      else
+        modemConfig_dialing = 'P';
+      S_LocalSound ("misc/menu1.wav");
+    }
+    break;
+
+  case K_ENTER:
+    if (modemConfig_cursor == 0)
+    {
+      if (modemConfig_dialing == 'P')
+        modemConfig_dialing = 'T';
+      else
+        modemConfig_dialing = 'P';
+      m_entersound = true;
+    }
+
+    if (modemConfig_cursor == 4)
+    {
+      (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
+      m_entersound = true;
+      M_Menu_SerialConfig_f ();
+    }
+    break;
+
+  case K_BACKSPACE:
+    if (modemConfig_cursor == 1)
+    {
+      if (strlen(modemConfig_clear))
+        modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
+    }
+
+    if (modemConfig_cursor == 2)
+    {
+      if (strlen(modemConfig_init))
+        modemConfig_init[strlen(modemConfig_init)-1] = 0;
+    }
+
+    if (modemConfig_cursor == 3)
+    {
+      if (strlen(modemConfig_hangup))
+        modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
+    }
+    break;
+
+  default:
+    if (key < 32 || key > 127)
+      break;
+
+    if (modemConfig_cursor == 1)
+    {
+      l = strlen(modemConfig_clear);
+      if (l < 15)
+      {
+        modemConfig_clear[l+1] = 0;
+        modemConfig_clear[l] = key;
+      }
+    }
+
+    if (modemConfig_cursor == 2)
+    {
+      l = strlen(modemConfig_init);
+      if (l < 29)
+      {
+        modemConfig_init[l+1] = 0;
+        modemConfig_init[l] = key;
+      }
+    }
+
+    if (modemConfig_cursor == 3)
+    {
+      l = strlen(modemConfig_hangup);
+      if (l < 15)
+      {
+        modemConfig_hangup[l+1] = 0;
+        modemConfig_hangup[l] = key;
+      }
+    }
+  }
+}
+
+//=============================================================================
+/* LAN CONFIG MENU */
+
+int		lanConfig_cursor = -1;
+int		lanConfig_cursor_table [] = {72, 92, 124};
+#define NUM_LANCONFIG_CMDS	3
+
+int 	lanConfig_port;
+char	lanConfig_portname[6];
+char	lanConfig_joinname[22];
+
+void M_Menu_LanConfig_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_lanconfig;
+  m_entersound = true;
+  if (lanConfig_cursor == -1)
+  {
+    if (JoiningGame && TCPIPConfig)
+      lanConfig_cursor = 2;
+    else
+      lanConfig_cursor = 1;
+  }
+  if (StartingGame && lanConfig_cursor == 2)
+    lanConfig_cursor = 1;
+  lanConfig_port = DEFAULTnet_hostport;
+  sprintf(lanConfig_portname, "%u", lanConfig_port);
+
+  m_return_onerror = false;
+  m_return_reason[0] = 0;
+}
+
+
+void M_LanConfig_Draw (void)
+{
+  qpic_t	*p;
+  int		basex;
+  const char	*startJoin;
+  const char	*protocol;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  basex = (320-p->width)/2;
+  M_DrawPic (basex, 4, p);
+
+  if (StartingGame)
+    startJoin = "New Game";
+  else
+    startJoin = "Join Game";
+  if (IPXConfig)
+    protocol = "IPX";
+  else
+    protocol = "TCP/IP";
+  M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
+  basex += 8;
+
+  M_Print (basex, 52, "Address:");
+  if (IPXConfig)
+    M_Print (basex+9*8, 52, my_ipx_address);
+  else
+    M_Print (basex+9*8, 52, my_tcpip_address);
+
+  M_Print (basex, lanConfig_cursor_table[0], "Port");
+  M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
+  M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
+
+  if (JoiningGame)
+  {
+    M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
+    M_Print (basex, 108, "Join game at:");
+    M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
+    M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
+  }
+  else
+  {
+    M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1);
+    M_Print (basex+8, lanConfig_cursor_table[1], "OK");
+  }
+
+  M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));
+
+  if (lanConfig_cursor == 0)
+    M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
+
+  if (lanConfig_cursor == 2)
+    M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
+
+  if (*m_return_reason)
+    M_PrintWhite (basex, 148, m_return_reason);
+}
+
+
+void M_LanConfig_Key (int key)
+{
+  int		l;
+
+  switch (key)
+  {
+  case K_ESCAPE:
+    M_Menu_Net_f ();
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    lanConfig_cursor--;
+    if (lanConfig_cursor < 0)
+      lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    lanConfig_cursor++;
+    if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
+      lanConfig_cursor = 0;
+    break;
+
+  case K_ENTER:
+    if (lanConfig_cursor == 0)
+      break;
+
+    m_entersound = true;
+
+    M_ConfigureNetSubsystem ();
+
+    if (lanConfig_cursor == 1)
+    {
+      if (StartingGame)
+      {
+        M_Menu_GameOptions_f ();
+        break;
+      }
+      M_Menu_Search_f();
+      break;
+    }
+
+    if (lanConfig_cursor == 2)
+    {
+      m_return_state = m_state;
+      m_return_onerror = true;
+      key_dest = key_game;
+      m_state = m_none;
+      Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
+      break;
+    }
+
+    break;
+
+  case K_BACKSPACE:
+    if (lanConfig_cursor == 0)
+    {
+      if (strlen(lanConfig_portname))
+        lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
+    }
+
+    if (lanConfig_cursor == 2)
+    {
+      if (strlen(lanConfig_joinname))
+        lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
+    }
+    break;
+
+  default:
+    if (key < 32 || key > 127)
+      break;
+
+    if (lanConfig_cursor == 2)
+    {
+      l = strlen(lanConfig_joinname);
+      if (l < 21)
+      {
+        lanConfig_joinname[l+1] = 0;
+        lanConfig_joinname[l] = key;
+      }
+    }
+
+    if (key < '0' || key > '9')
+      break;
+    if (lanConfig_cursor == 0)
+    {
+      l = strlen(lanConfig_portname);
+      if (l < 5)
+      {
+        lanConfig_portname[l+1] = 0;
+        lanConfig_portname[l] = key;
+      }
+    }
+  }
+
+  if (StartingGame && lanConfig_cursor == 2)
+  {
+    if (key == K_UPARROW)
+      lanConfig_cursor = 1;
+    else
+      lanConfig_cursor = 0;
+  }
+
+  l =  Q_atoi(lanConfig_portname);
+  if (l > 65535)
+    l = lanConfig_port;
+  else
+    lanConfig_port = l;
+  sprintf(lanConfig_portname, "%u", lanConfig_port);
+}
+
+//=============================================================================
+/* GAME OPTIONS MENU */
+
+typedef struct
+{
+  const char	*name;
+  const char	*description;
+} level_t;
+
+level_t		levels[] =
+{
+  {"start", "Entrance"},	// 0
+
+  {"e1m1", "Slipgate Complex"},				// 1
+  {"e1m2", "Castle of the Damned"},
+  {"e1m3", "The Necropolis"},
+  {"e1m4", "The Grisly Grotto"},
+  {"e1m5", "Gloom Keep"},
+  {"e1m6", "The Door To Chthon"},
+  {"e1m7", "The House of Chthon"},
+  {"e1m8", "Ziggurat Vertigo"},
+
+  {"e2m1", "The Installation"},				// 9
+  {"e2m2", "Ogre Citadel"},
+  {"e2m3", "Crypt of Decay"},
+  {"e2m4", "The Ebon Fortress"},
+  {"e2m5", "The Wizard's Manse"},
+  {"e2m6", "The Dismal Oubliette"},
+  {"e2m7", "Underearth"},
+
+  {"e3m1", "Termination Central"},			// 16
+  {"e3m2", "The Vaults of Zin"},
+  {"e3m3", "The Tomb of Terror"},
+  {"e3m4", "Satan's Dark Delight"},
+  {"e3m5", "Wind Tunnels"},
+  {"e3m6", "Chambers of Torment"},
+  {"e3m7", "The Haunted Halls"},
+
+  {"e4m1", "The Sewage System"},				// 23
+  {"e4m2", "The Tower of Despair"},
+  {"e4m3", "The Elder God Shrine"},
+  {"e4m4", "The Palace of Hate"},
+  {"e4m5", "Hell's Atrium"},
+  {"e4m6", "The Pain Maze"},
+  {"e4m7", "Azure Agony"},
+  {"e4m8", "The Nameless City"},
+
+  {"end", "Shub-Niggurath's Pit"},			// 31
+
+  {"dm1", "Place of Two Deaths"},				// 32
+  {"dm2", "Claustrophobopolis"},
+  {"dm3", "The Abandoned Base"},
+  {"dm4", "The Bad Place"},
+  {"dm5", "The Cistern"},
+  {"dm6", "The Dark Zone"}
+};
+
+//MED 01/06/97 added hipnotic levels
+level_t     hipnoticlevels[] =
+{
+   {"start", "Command HQ"},  // 0
+
+   {"hip1m1", "The Pumping Station"},          // 1
+   {"hip1m2", "Storage Facility"},
+   {"hip1m3", "The Lost Mine"},
+   {"hip1m4", "Research Facility"},
+   {"hip1m5", "Military Complex"},
+
+   {"hip2m1", "Ancient Realms"},          // 6
+   {"hip2m2", "The Black Cathedral"},
+   {"hip2m3", "The Catacombs"},
+   {"hip2m4", "The Crypt"},
+   {"hip2m5", "Mortum's Keep"},
+   {"hip2m6", "The Gremlin's Domain"},
+
+   {"hip3m1", "Tur Torment"},       // 12
+   {"hip3m2", "Pandemonium"},
+   {"hip3m3", "Limbo"},
+   {"hip3m4", "The Gauntlet"},
+
+   {"hipend", "Armagon's Lair"},       // 16
+
+   {"hipdm1", "The Edge of Oblivion"}           // 17
+};
+
+//PGM 01/07/97 added rogue levels
+//PGM 03/02/97 added dmatch level
+level_t		roguelevels[] =
+{
+  {"start",	"Split Decision"},
+  {"r1m1",	"Deviant's Domain"},
+  {"r1m2",	"Dread Portal"},
+  {"r1m3",	"Judgement Call"},
+  {"r1m4",	"Cave of Death"},
+  {"r1m5",	"Towers of Wrath"},
+  {"r1m6",	"Temple of Pain"},
+  {"r1m7",	"Tomb of the Overlord"},
+  {"r2m1",	"Tempus Fugit"},
+  {"r2m2",	"Elemental Fury I"},
+  {"r2m3",	"Elemental Fury II"},
+  {"r2m4",	"Curse of Osiris"},
+  {"r2m5",	"Wizard's Keep"},
+  {"r2m6",	"Blood Sacrifice"},
+  {"r2m7",	"Last Bastion"},
+  {"r2m8",	"Source of Evil"},
+  {"ctf1",    "Division of Change"}
+};
+
+typedef struct
+{
+  const char	*description;
+  int		firstLevel;
+  int		levels;
+} episode_t;
+
+episode_t	episodes[] =
+{
+  {"Welcome to Quake", 0, 1},
+  {"Doomed Dimension", 1, 8},
+  {"Realm of Black Magic", 9, 7},
+  {"Netherworld", 16, 7},
+  {"The Elder World", 23, 8},
+  {"Final Level", 31, 1},
+  {"Deathmatch Arena", 32, 6}
+};
+
+//MED 01/06/97  added hipnotic episodes
+episode_t   hipnoticepisodes[] =
+{
+   {"Scourge of Armagon", 0, 1},
+   {"Fortress of the Dead", 1, 5},
+   {"Dominion of Darkness", 6, 6},
+   {"The Rift", 12, 4},
+   {"Final Level", 16, 1},
+   {"Deathmatch Arena", 17, 1}
+};
+
+//PGM 01/07/97 added rogue episodes
+//PGM 03/02/97 added dmatch episode
+episode_t	rogueepisodes[] =
+{
+  {"Introduction", 0, 1},
+  {"Hell's Fortress", 1, 7},
+  {"Corridors of Time", 8, 8},
+  {"Deathmatch Arena", 16, 1}
+};
+
+int	startepisode;
+int	startlevel;
+int maxplayers;
+qboolean m_serverInfoMessage = false;
+double m_serverInfoMessageTime;
+
+void M_Menu_GameOptions_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_gameoptions;
+  m_entersound = true;
+  if (maxplayers == 0)
+    maxplayers = svs.maxclients;
+  if (maxplayers < 2)
+    maxplayers = svs.maxclientslimit;
+}
+
+
+int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
+#define	NUM_GAMEOPTIONS	9
+int		gameoptions_cursor;
+
+void M_GameOptions_Draw (void)
+{
+  qpic_t	*p;
+  int		x;
+
+  M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+
+  M_DrawTextBox (152, 32, 10, 1);
+  M_Print (160, 40, "begin game");
+
+  M_Print (0, 56, "      Max players");
+  M_Print (160, 56, va("%i", maxplayers) );
+
+  M_Print (0, 64, "        Game Type");
+  if (coop.value)
+    M_Print (160, 64, "Cooperative");
+  else
+    M_Print (160, 64, "Deathmatch");
+
+  M_Print (0, 72, "        Teamplay");
+  if (rogue)
+  {
+    const char *msg;
+
+    switch((int)teamplay.value)
+    {
+      case 1: msg = "No Friendly Fire"; break;
+      case 2: msg = "Friendly Fire"; break;
+      case 3: msg = "Tag"; break;
+      case 4: msg = "Capture the Flag"; break;
+      case 5: msg = "One Flag CTF"; break;
+      case 6: msg = "Three Team CTF"; break;
+      default: msg = "Off"; break;
+    }
+    M_Print (160, 72, msg);
+  }
+  else
+  {
+    const char *msg;
+
+    switch((int)teamplay.value)
+    {
+      case 1: msg = "No Friendly Fire"; break;
+      case 2: msg = "Friendly Fire"; break;
+      default: msg = "Off"; break;
+    }
+    M_Print (160, 72, msg);
+  }
+
+  M_Print (0, 80, "            Skill");
+  if (skill.value == 0)
+    M_Print (160, 80, "Easy difficulty");
+  else if (skill.value == 1)
+    M_Print (160, 80, "Normal difficulty");
+  else if (skill.value == 2)
+    M_Print (160, 80, "Hard difficulty");
+  else
+    M_Print (160, 80, "Nightmare difficulty");
+
+  M_Print (0, 88, "       Frag Limit");
+  if (fraglimit.value == 0)
+    M_Print (160, 88, "none");
+  else
+    M_Print (160, 88, va("%i frags", (int)fraglimit.value));
+
+  M_Print (0, 96, "       Time Limit");
+  if (timelimit.value == 0)
+    M_Print (160, 96, "none");
+  else
+    M_Print (160, 96, va("%i minutes", (int)timelimit.value));
+
+  M_Print (0, 112, "         Episode");
+   //MED 01/06/97 added hipnotic episodes
+   if (hipnotic)
+      M_Print (160, 112, hipnoticepisodes[startepisode].description);
+   //PGM 01/07/97 added rogue episodes
+   else if (rogue)
+      M_Print (160, 112, rogueepisodes[startepisode].description);
+   else
+      M_Print (160, 112, episodes[startepisode].description);
+
+  M_Print (0, 120, "           Level");
+   //MED 01/06/97 added hipnotic episodes
+   if (hipnotic)
+   {
+      M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
+      M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
+   }
+   //PGM 01/07/97 added rogue episodes
+   else if (rogue)
+   {
+      M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
+      M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
+   }
+   else
+   {
+      M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
+      M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
+   }
+
+// line cursor
+  M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
+
+  if (m_serverInfoMessage)
+  {
+    if ((realtime - m_serverInfoMessageTime) < 5.0)
+    {
+      x = (320-26*8)/2;
+      M_DrawTextBox (x, 138, 24, 4);
+      x += 8;
+      M_Print (x, 146, "  More than 4 players   ");
+      M_Print (x, 154, " requires using command ");
+      M_Print (x, 162, "line parameters; please ");
+      M_Print (x, 170, "   see techinfo.txt.    ");
+    }
+    else
+    {
+      m_serverInfoMessage = false;
+    }
+  }
+}
+
+
+void M_NetStart_Change (int dir)
+{
+  int count;
+
+  switch (gameoptions_cursor)
+  {
+  case 1:
+    maxplayers += dir;
+    if (maxplayers > svs.maxclientslimit)
+    {
+      maxplayers = svs.maxclientslimit;
+      m_serverInfoMessage = true;
+      m_serverInfoMessageTime = realtime;
+    }
+    if (maxplayers < 2)
+      maxplayers = 2;
+    break;
+
+  case 2:
+    Cvar_SetValue ("coop", coop.value ? 0 : 1);
+    break;
+
+  case 3:
+    if (rogue)
+      count = 6;
+    else
+      count = 2;
+
+    Cvar_SetValue ("teamplay", teamplay.value + dir);
+    if (teamplay.value > count)
+      Cvar_SetValue ("teamplay", 0);
+    else if (teamplay.value < 0)
+      Cvar_SetValue ("teamplay", count);
+    break;
+
+  case 4:
+    Cvar_SetValue ("skill", skill.value + dir);
+    if (skill.value > 3)
+      Cvar_SetValue ("skill", 0);
+    if (skill.value < 0)
+      Cvar_SetValue ("skill", 3);
+    break;
+
+  case 5:
+    Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
+    if (fraglimit.value > 100)
+      Cvar_SetValue ("fraglimit", 0);
+    if (fraglimit.value < 0)
+      Cvar_SetValue ("fraglimit", 100);
+    break;
+
+  case 6:
+    Cvar_SetValue ("timelimit", timelimit.value + dir*5);
+    if (timelimit.value > 60)
+      Cvar_SetValue ("timelimit", 0);
+    if (timelimit.value < 0)
+      Cvar_SetValue ("timelimit", 60);
+    break;
+
+  case 7:
+    startepisode += dir;
+  //MED 01/06/97 added hipnotic count
+    if (hipnotic)
+      count = 6;
+  //PGM 01/07/97 added rogue count
+  //PGM 03/02/97 added 1 for dmatch episode
+    else if (rogue)
+      count = 4;
+    else if (registered.value)
+      count = 7;
+    else
+      count = 2;
+
+    if (startepisode < 0)
+      startepisode = count - 1;
+
+    if (startepisode >= count)
+      startepisode = 0;
+
+    startlevel = 0;
+    break;
+
+  case 8:
+    startlevel += dir;
+    //MED 01/06/97 added hipnotic episodes
+    if (hipnotic)
+      count = hipnoticepisodes[startepisode].levels;
+  //PGM 01/06/97 added hipnotic episodes
+    else if (rogue)
+      count = rogueepisodes[startepisode].levels;
+    else
+      count = episodes[startepisode].levels;
+
+    if (startlevel < 0)
+      startlevel = count - 1;
+
+    if (startlevel >= count)
+      startlevel = 0;
+    break;
+  }
+}
+
+void M_GameOptions_Key (int key)
+{
+  switch (key)
+  {
+  case K_ESCAPE:
+    M_Menu_Net_f ();
+    break;
+
+  case K_UPARROW:
+    S_LocalSound ("misc/menu1.wav");
+    gameoptions_cursor--;
+    if (gameoptions_cursor < 0)
+      gameoptions_cursor = NUM_GAMEOPTIONS-1;
+    break;
+
+  case K_DOWNARROW:
+    S_LocalSound ("misc/menu1.wav");
+    gameoptions_cursor++;
+    if (gameoptions_cursor >= NUM_GAMEOPTIONS)
+      gameoptions_cursor = 0;
+    break;
+
+  case K_LEFTARROW:
+    if (gameoptions_cursor == 0)
+      break;
+    S_LocalSound ("misc/menu3.wav");
+    M_NetStart_Change (-1);
+    break;
+
+  case K_RIGHTARROW:
+    if (gameoptions_cursor == 0)
+      break;
+    S_LocalSound ("misc/menu3.wav");
+    M_NetStart_Change (1);
+    break;
+
+  case K_ENTER:
+    S_LocalSound ("misc/menu2.wav");
+    if (gameoptions_cursor == 0)
+    {
+      if (sv.active)
+        Cbuf_AddText ("disconnect\n");
+      Cbuf_AddText ("listen 0\n");	// so host_netport will be re-examined
+      Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
+      SCR_BeginLoadingPlaque ();
+
+      if (hipnotic)
+        Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );
+      else if (rogue)
+        Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );
+      else
+        Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) );
+
+      return;
+    }
+
+    M_NetStart_Change (1);
+    break;
+  }
+}
+
+//=============================================================================
+/* SEARCH MENU */
+
+qboolean	searchComplete = false;
+double		searchCompleteTime;
+
+void M_Menu_Search_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_search;
+  m_entersound = false;
+  slistSilent = true;
+  slistLocal = false;
+  searchComplete = false;
+  NET_Slist_f();
+
+}
+
+
+void M_Search_Draw (void)
+{
+  qpic_t	*p;
+  int x;
+
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+  x = (320/2) - ((12*8)/2) + 4;
+  M_DrawTextBox (x-8, 32, 12, 1);
+  M_Print (x, 40, "Searching...");
+
+  if(slistInProgress)
+  {
+    NET_Poll();
+    return;
+  }
+
+  if (! searchComplete)
+  {
+    searchComplete = true;
+    searchCompleteTime = realtime;
+  }
+
+  if (hostCacheCount)
+  {
+    M_Menu_ServerList_f ();
+    return;
+  }
+
+  M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
+  if ((realtime - searchCompleteTime) < 3.0)
+    return;
+
+  M_Menu_LanConfig_f ();
+}
+
+
+void M_Search_Key (int key)
+{
+}
+
+//=============================================================================
+/* SLIST MENU */
+
+int		slist_cursor;
+qboolean slist_sorted;
+
+void M_Menu_ServerList_f (void)
+{
+  key_dest = key_menu;
+  m_state = m_slist;
+  m_entersound = true;
+  slist_cursor = 0;
+  m_return_onerror = false;
+  m_return_reason[0] = 0;
+  slist_sorted = false;
+}
+
+
+void M_ServerList_Draw (void)
+{
+  int		n;
+  char	string [64];
+  qpic_t	*p;
+
+  if (!slist_sorted)
+  {
+    if (hostCacheCount > 1)
+    {
+      int	i,j;
+      hostcache_t temp;
+      for (i = 0; i < hostCacheCount; i++)
+        for (j = i+1; j < hostCacheCount; j++)
+          if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
+          {
+            Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
+            Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
+            Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
+          }
+    }
+    slist_sorted = true;
+  }
+
+  p = Draw_CachePic ("gfx/p_multi.lmp");
+  M_DrawPic ( (320-p->width)/2, 4, p);
+  for (n = 0; n < hostCacheCount; n++)
+  {
+    if (hostcache[n].maxusers)
+      sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
+    else
+      sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
+    M_Print (16, 32 + 8*n, string);
+  }
+  M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
+
+  if (*m_return_reason)
+    M_PrintWhite (16, 148, m_return_reason);
+}
+
+
+void M_ServerList_Key (int k)
+{
+  switch (k)
+  {
+  case K_ESCAPE:
+    M_Menu_LanConfig_f ();
+    break;
+
+  case K_SPACE:
+    M_Menu_Search_f ();
+    break;
+
+  case K_UPARROW:
+  case K_LEFTARROW:
+    S_LocalSound ("misc/menu1.wav");
+    slist_cursor--;
+    if (slist_cursor < 0)
+      slist_cursor = hostCacheCount - 1;
+    break;
+
+  case K_DOWNARROW:
+  case K_RIGHTARROW:
+    S_LocalSound ("misc/menu1.wav");
+    slist_cursor++;
+    if (slist_cursor >= hostCacheCount)
+      slist_cursor = 0;
+    break;
+
+  case K_ENTER:
+    S_LocalSound ("misc/menu2.wav");
+    m_return_state = m_state;
+    m_return_onerror = true;
+    slist_sorted = false;
+    key_dest = key_game;
+    m_state = m_none;
+    Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
+    break;
+
+  default:
+    break;
+  }
+
+}
+
+//=============================================================================
+/* Menu Subsystem */
+
+
+void M_Init (void)
+{
+  Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
+
+  Cmd_AddCommand ("menu_main", M_Menu_Main_f);
+  Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
+  Cmd_AddCommand ("menu_load", M_Menu_Load_f);
+  Cmd_AddCommand ("menu_save", M_Menu_Save_f);
+  Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
+  Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
+  Cmd_AddCommand ("menu_options", M_Menu_Options_f);
+  Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
+  Cmd_AddCommand ("menu_video", M_Menu_Video_f);
+  Cmd_AddCommand ("help", M_Menu_Help_f);
+  Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
+}
+
+
+void M_Draw (void)
+{
+  if (m_state == m_none || key_dest != key_menu)
+    return;
+
+  if (!m_recursiveDraw)
+  {
+    scr_copyeverything = 1;
+
+    if (scr_con_current)
+    {
+      Draw_ConsoleBackground (vid.height);
+      VID_UnlockBuffer ();
+      S_ExtraUpdate ();
+      VID_LockBuffer ();
+    }
+    else
+      Draw_FadeScreen ();
+
+    scr_fullupdate = 0;
+  }
+  else
+  {
+    m_recursiveDraw = false;
+  }
+
+  switch (m_state)
+  {
+  case m_none:
+    break;
+
+  case m_main:
+    M_Main_Draw ();
+    break;
+
+  case m_singleplayer:
+    M_SinglePlayer_Draw ();
+    break;
+
+  case m_load:
+    M_Load_Draw ();
+    break;
+
+  case m_save:
+    M_Save_Draw ();
+    break;
+
+  case m_multiplayer:
+    M_MultiPlayer_Draw ();
+    break;
+
+  case m_setup:
+    M_Setup_Draw ();
+    break;
+
+  case m_net:
+    M_Net_Draw ();
+    break;
+
+  case m_options:
+    M_Options_Draw ();
+    break;
+
+  case m_keys:
+    M_Keys_Draw ();
+    break;
+
+  case m_video:
+    M_Video_Draw ();
+    break;
+
+  case m_help:
+    M_Help_Draw ();
+    break;
+
+  case m_quit:
+    M_Quit_Draw ();
+    break;
+
+  case m_serialconfig:
+    M_SerialConfig_Draw ();
+    break;
+
+  case m_modemconfig:
+    M_ModemConfig_Draw ();
+    break;
+
+  case m_lanconfig:
+    M_LanConfig_Draw ();
+    break;
+
+  case m_gameoptions:
+    M_GameOptions_Draw ();
+    break;
+
+  case m_search:
+    M_Search_Draw ();
+    break;
+
+  case m_slist:
+    M_ServerList_Draw ();
+    break;
+  }
+
+  if (m_entersound)
+  {
+    S_LocalSound ("misc/menu2.wav");
+    m_entersound = false;
+  }
+
+  VID_UnlockBuffer ();
+  S_ExtraUpdate ();
+  VID_LockBuffer ();
+}
+
+
+void M_Keydown (int key)
+{
+  switch (m_state)
+  {
+  case m_none:
+    return;
+
+  case m_main:
+    M_Main_Key (key);
+    return;
+
+  case m_singleplayer:
+    M_SinglePlayer_Key (key);
+    return;
+
+  case m_load:
+    M_Load_Key (key);
+    return;
+
+  case m_save:
+    M_Save_Key (key);
+    return;
+
+  case m_multiplayer:
+    M_MultiPlayer_Key (key);
+    return;
+
+  case m_setup:
+    M_Setup_Key (key);
+    return;
+
+  case m_net:
+    M_Net_Key (key);
+    return;
+
+  case m_options:
+    M_Options_Key (key);
+    return;
+
+  case m_keys:
+    M_Keys_Key (key);
+    return;
+
+  case m_video:
+    M_Video_Key (key);
+    return;
+
+  case m_help:
+    M_Help_Key (key);
+    return;
+
+  case m_quit:
+    M_Quit_Key (key);
+    return;
+
+  case m_serialconfig:
+    M_SerialConfig_Key (key);
+    return;
+
+  case m_modemconfig:
+    M_ModemConfig_Key (key);
+    return;
+
+  case m_lanconfig:
+    M_LanConfig_Key (key);
+    return;
+
+  case m_gameoptions:
+    M_GameOptions_Key (key);
+    return;
+
+  case m_search:
+    M_Search_Key (key);
+    break;
+
+  case m_slist:
+    M_ServerList_Key (key);
+    return;
+  }
+}
+
+
+void M_ConfigureNetSubsystem(void)
+{
+// enable/disable net systems to match desired config
+
+  Cbuf_AddText ("stopdemo\n");
+  if (SerialConfig || DirectConfig)
+  {
+    Cbuf_AddText ("com1 enable\n");
+  }
+
+  if (IPXConfig || TCPIPConfig)
+    net_hostport = lanConfig_port;
+}
diff --git a/quake/src/WinQuake/model.c b/quake/src/WinQuake/model.cpp
old mode 100644
new mode 100755
similarity index 99%
rename from quake/src/WinQuake/model.c
rename to quake/src/WinQuake/model.cpp
index c708c86..2041f63
--- a/quake/src/WinQuake/model.c
+++ b/quake/src/WinQuake/model.cpp
@@ -1,1874 +1,1874 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// models.c -- model loading and caching

-

-// models are the only shared resource between a client and server running

-// on the same machine.

-

-#include "quakedef.h"

-#include "r_local.h"

-

-model_t	*loadmodel;

-char	loadname[32];	// for hunk tags

-

-void Mod_LoadSpriteModel (model_t *mod, void *buffer);

-void Mod_LoadBrushModel (model_t *mod, void *buffer);

-void Mod_LoadAliasModel (model_t *mod, void *buffer);

-model_t *Mod_LoadModel (model_t *mod, qboolean crash);

-

-byte	mod_novis[MAX_MAP_LEAFS/8];

-

-#define	MAX_MOD_KNOWN	256

-model_t	mod_known[MAX_MOD_KNOWN];

-int		mod_numknown;

-

-// values for model_t's needload

-#define NL_PRESENT		0

-#define NL_NEEDS_LOADED	1

-#define NL_UNREFERENCED	2

-

-/*

-===============

-Mod_Init

-===============

-*/

-void Mod_Init (void)

-{

-	memset (mod_novis, 0xff, sizeof(mod_novis));

-}

-

-/*

-===============

-Mod_Extradata

-

-Caches the data if needed

-===============

-*/

-void *Mod_Extradata (model_t *mod)

-{

-	void	*r;

-	

-	r = Cache_Check (&mod->cache);

-	if (r)

-		return r;

-

-	Mod_LoadModel (mod, true);

-	

-	if (!mod->cache.data)

-		Sys_Error ("Mod_Extradata: caching failed");

-	return mod->cache.data;

-}

-

-/*

-===============

-Mod_PointInLeaf

-===============

-*/

-mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)

-{

-	mnode_t		*node;

-	float		d;

-	mplane_t	*plane;

-	

-	if (!model || !model->nodes)

-		Sys_Error ("Mod_PointInLeaf: bad model");

-

-	node = model->nodes;

-	while (1)

-	{

-		if (node->contents < 0)

-			return (mleaf_t *)node;

-		plane = node->plane;

-		d = DotProduct (p,plane->normal) - plane->dist;

-		if (d > 0)

-			node = node->children[0];

-		else

-			node = node->children[1];

-	}

-	

-	return NULL;	// never reached

-}

-

-

-/*

-===================

-Mod_DecompressVis

-===================

-*/

-byte *Mod_DecompressVis (byte *in, model_t *model)

-{

-	static byte	decompressed[MAX_MAP_LEAFS/8];

-	int		c;

-	byte	*out;

-	int		row;

-

-	row = (model->numleafs+7)>>3;	

-	out = decompressed;

-

-	if (!in)

-	{	// no vis info, so make all visible

-		while (row)

-		{

-			*out++ = 0xff;

-			row--;

-		}

-		return decompressed;		

-	}

-

-	do

-	{

-		if (*in)

-		{

-			*out++ = *in++;

-			continue;

-		}

-	

-		c = in[1];

-		in += 2;

-		while (c)

-		{

-			*out++ = 0;

-			c--;

-		}

-	} while (out - decompressed < row);

-	

-	return decompressed;

-}

-

-byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)

-{

-	if (leaf == model->leafs)

-		return mod_novis;

-	return Mod_DecompressVis (leaf->compressed_vis, model);

-}

-

-/*

-===================

-Mod_ClearAll

-===================

-*/

-void Mod_ClearAll (void)

-{

-	int		i;

-	model_t	*mod;

-

-

-	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) {

-		mod->needload = NL_UNREFERENCED;

-//FIX FOR CACHE_ALLOC ERRORS:

-		if (mod->type == mod_sprite) mod->cache.data = NULL;

-	}

-}

-

-/*

-==================

-Mod_FindName

-

-==================

-*/

-model_t *Mod_FindName (char *name)

-{

-	int		i;

-	model_t	*mod;

-	model_t	*avail = NULL;

-

-	if (!name[0])

-		Sys_Error ("Mod_ForName: NULL name");

-		

-//

-// search the currently loaded models

-//

-	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)

-	{

-		if (!strcmp (mod->name, name) )

-			break;

-		if (mod->needload == NL_UNREFERENCED)

-			if (!avail || mod->type != mod_alias)

-				avail = mod;

-	}

-			

-	if (i == mod_numknown)

-	{

-		if (mod_numknown == MAX_MOD_KNOWN)

-		{

-			if (avail)

-			{

-				mod = avail;

-				if (mod->type == mod_alias)

-					if (Cache_Check (&mod->cache))

-						Cache_Free (&mod->cache);

-			}

-			else

-				Sys_Error ("mod_numknown == MAX_MOD_KNOWN");

-		}

-		else

-			mod_numknown++;

-		strcpy (mod->name, name);

-		mod->needload = NL_NEEDS_LOADED;

-	}

-

-	return mod;

-}

-

-/*

-==================

-Mod_TouchModel

-

-==================

-*/

-void Mod_TouchModel (char *name)

-{

-	model_t	*mod;

-	

-	mod = Mod_FindName (name);

-	

-	if (mod->needload == NL_PRESENT)

-	{

-		if (mod->type == mod_alias)

-			Cache_Check (&mod->cache);

-	}

-}

-

-/*

-==================

-Mod_LoadModel

-

-Loads a model into the cache

-==================

-*/

-model_t *Mod_LoadModel (model_t *mod, qboolean crash)

-{

-	unsigned *buf;

-	byte	stackbuf[1024];		// avoid dirtying the cache heap

-

-	if (mod->type == mod_alias)

-	{

-		if (Cache_Check (&mod->cache))

-		{

-			mod->needload = NL_PRESENT;

-			return mod;

-		}

-	}

-	else

-	{

-		if (mod->needload == NL_PRESENT)

-			return mod;

-	}

-

-//

-// because the world is so huge, load it one piece at a time

-//

-	

-//

-// load the file

-//

-	buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf));

-	if (!buf)

-	{

-		if (crash)

-			Sys_Error ("Mod_NumForName: %s not found", mod->name);

-		return NULL;

-	}

-	

-//

-// allocate a new model

-//

-	COM_FileBase (mod->name, loadname);

-	

-	loadmodel = mod;

-

-//

-// fill it in

-//

-

-// call the apropriate loader

-	mod->needload = NL_PRESENT;

-

-	switch (LittleLong(*(unsigned *)buf))

-	{

-	case IDPOLYHEADER:

-		Mod_LoadAliasModel (mod, buf);

-		break;

-		

-	case IDSPRITEHEADER:

-		Mod_LoadSpriteModel (mod, buf);

-		break;

-	

-	default:

-		Mod_LoadBrushModel (mod, buf);

-		break;

-	}

-

-	return mod;

-}

-

-/*

-==================

-Mod_ForName

-

-Loads in a model for the given name

-==================

-*/

-model_t *Mod_ForName (char *name, qboolean crash)

-{

-	model_t	*mod;

-

-	mod = Mod_FindName (name);

-

-	return Mod_LoadModel (mod, crash);

-}

-

-

-/*

-===============================================================================

-

-					BRUSHMODEL LOADING

-

-===============================================================================

-*/

-

-byte	*mod_base;

-

-

-/*

-=================

-Mod_LoadTextures

-=================

-*/

-void Mod_LoadTextures (lump_t *l)

-{

-	int		i, j, pixels, num, max, altmax;

-	miptex_t	*mt;

-	texture_t	*tx, *tx2;

-	texture_t	*anims[10];

-	texture_t	*altanims[10];

-	dmiptexlump_t *m;

-

-	if (!l->filelen)

-	{

-		loadmodel->textures = NULL;

-		return;

-	}

-	m = (dmiptexlump_t *)(mod_base + l->fileofs);

-	

-	m->nummiptex = LittleLong (m->nummiptex);

-	

-	loadmodel->numtextures = m->nummiptex;

-	loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);

-

-	for (i=0 ; i<m->nummiptex ; i++)

-	{

-		m->dataofs[i] = LittleLong(m->dataofs[i]);

-		if (m->dataofs[i] == -1)

-			continue;

-		mt = (miptex_t *)((byte *)m + m->dataofs[i]);

-		mt->width = LittleLong (mt->width);

-		mt->height = LittleLong (mt->height);

-		for (j=0 ; j<MIPLEVELS ; j++)

-			mt->offsets[j] = LittleLong (mt->offsets[j]);

-		

-		if ( (mt->width & 15) || (mt->height & 15) )

-			Sys_Error ("Texture %s is not 16 aligned", mt->name);

-		pixels = mt->width*mt->height/64*85;

-		tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );

-		loadmodel->textures[i] = tx;

-

-		memcpy (tx->name, mt->name, sizeof(tx->name));

-		tx->width = mt->width;

-		tx->height = mt->height;

-		for (j=0 ; j<MIPLEVELS ; j++)

-			tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);

-		// the pixels immediately follow the structures

-		memcpy ( tx+1, mt+1, pixels);

-		

-		if (!Q_strncmp(mt->name,"sky",3))	

-			R_InitSky (tx);

-	}

-

-//

-// sequence the animations

-//

-	for (i=0 ; i<m->nummiptex ; i++)

-	{

-		tx = loadmodel->textures[i];

-		if (!tx || tx->name[0] != '+')

-			continue;

-		if (tx->anim_next)

-			continue;	// allready sequenced

-

-	// find the number of frames in the animation

-		memset (anims, 0, sizeof(anims));

-		memset (altanims, 0, sizeof(altanims));

-

-		max = tx->name[1];

-		altmax = 0;

-		if (max >= 'a' && max <= 'z')

-			max -= 'a' - 'A';

-		if (max >= '0' && max <= '9')

-		{

-			max -= '0';

-			altmax = 0;

-			anims[max] = tx;

-			max++;

-		}

-		else if (max >= 'A' && max <= 'J')

-		{

-			altmax = max - 'A';

-			max = 0;

-			altanims[altmax] = tx;

-			altmax++;

-		}

-		else

-			Sys_Error ("Bad animating texture %s", tx->name);

-

-		for (j=i+1 ; j<m->nummiptex ; j++)

-		{

-			tx2 = loadmodel->textures[j];

-			if (!tx2 || tx2->name[0] != '+')

-				continue;

-			if (strcmp (tx2->name+2, tx->name+2))

-				continue;

-

-			num = tx2->name[1];

-			if (num >= 'a' && num <= 'z')

-				num -= 'a' - 'A';

-			if (num >= '0' && num <= '9')

-			{

-				num -= '0';

-				anims[num] = tx2;

-				if (num+1 > max)

-					max = num + 1;

-			}

-			else if (num >= 'A' && num <= 'J')

-			{

-				num = num - 'A';

-				altanims[num] = tx2;

-				if (num+1 > altmax)

-					altmax = num+1;

-			}

-			else

-				Sys_Error ("Bad animating texture %s", tx->name);

-		}

-		

-#define	ANIM_CYCLE	2

-	// link them all together

-		for (j=0 ; j<max ; j++)

-		{

-			tx2 = anims[j];

-			if (!tx2)

-				Sys_Error ("Missing frame %i of %s",j, tx->name);

-			tx2->anim_total = max * ANIM_CYCLE;

-			tx2->anim_min = j * ANIM_CYCLE;

-			tx2->anim_max = (j+1) * ANIM_CYCLE;

-			tx2->anim_next = anims[ (j+1)%max ];

-			if (altmax)

-				tx2->alternate_anims = altanims[0];

-		}

-		for (j=0 ; j<altmax ; j++)

-		{

-			tx2 = altanims[j];

-			if (!tx2)

-				Sys_Error ("Missing frame %i of %s",j, tx->name);

-			tx2->anim_total = altmax * ANIM_CYCLE;

-			tx2->anim_min = j * ANIM_CYCLE;

-			tx2->anim_max = (j+1) * ANIM_CYCLE;

-			tx2->anim_next = altanims[ (j+1)%altmax ];

-			if (max)

-				tx2->alternate_anims = anims[0];

-		}

-	}

-}

-

-/*

-=================

-Mod_LoadLighting

-=================

-*/

-void Mod_LoadLighting (lump_t *l)

-{

-	if (!l->filelen)

-	{

-		loadmodel->lightdata = NULL;

-		return;

-	}

-	loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);	

-	memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);

-}

-

-

-/*

-=================

-Mod_LoadVisibility

-=================

-*/

-void Mod_LoadVisibility (lump_t *l)

-{

-	if (!l->filelen)

-	{

-		loadmodel->visdata = NULL;

-		return;

-	}

-	loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname);	

-	memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);

-}

-

-

-/*

-=================

-Mod_LoadEntities

-=================

-*/

-void Mod_LoadEntities (lump_t *l)

-{

-	if (!l->filelen)

-	{

-		loadmodel->entities = NULL;

-		return;

-	}

-	loadmodel->entities = Hunk_AllocName ( l->filelen, loadname);	

-	memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);

-}

-

-

-/*

-=================

-Mod_LoadVertexes

-=================

-*/

-void Mod_LoadVertexes (lump_t *l)

-{

-	dvertex_t	*in;

-	mvertex_t	*out;

-	int			i, count;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->vertexes = out;

-	loadmodel->numvertexes = count;

-

-	for ( i=0 ; i<count ; i++, in++, out++)

-	{

-		out->position[0] = LittleFloat (in->point[0]);

-		out->position[1] = LittleFloat (in->point[1]);

-		out->position[2] = LittleFloat (in->point[2]);

-	}

-}

-

-/*

-=================

-Mod_LoadSubmodels

-=================

-*/

-void Mod_LoadSubmodels (lump_t *l)

-{

-	dmodel_t	*in;

-	dmodel_t	*out;

-	int			i, j, count;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->submodels = out;

-	loadmodel->numsubmodels = count;

-

-	for ( i=0 ; i<count ; i++, in++, out++)

-	{

-		for (j=0 ; j<3 ; j++)

-		{	// spread the mins / maxs by a pixel

-			out->mins[j] = LittleFloat (in->mins[j]) - 1;

-			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;

-			out->origin[j] = LittleFloat (in->origin[j]);

-		}

-		for (j=0 ; j<MAX_MAP_HULLS ; j++)

-			out->headnode[j] = LittleLong (in->headnode[j]);

-		out->visleafs = LittleLong (in->visleafs);

-		out->firstface = LittleLong (in->firstface);

-		out->numfaces = LittleLong (in->numfaces);

-	}

-}

-

-/*

-=================

-Mod_LoadEdges

-=================

-*/

-void Mod_LoadEdges (lump_t *l)

-{

-	dedge_t *in;

-	medge_t *out;

-	int 	i, count;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);	

-

-	loadmodel->edges = out;

-	loadmodel->numedges = count;

-

-	for ( i=0 ; i<count ; i++, in++, out++)

-	{

-		out->v[0] = (unsigned short)LittleShort(in->v[0]);

-		out->v[1] = (unsigned short)LittleShort(in->v[1]);

-	}

-}

-

-/*

-=================

-Mod_LoadTexinfo

-=================

-*/

-void Mod_LoadTexinfo (lump_t *l)

-{

-	texinfo_t *in;

-	mtexinfo_t *out;

-	int 	i, j, count;

-	int		miptex;

-	float	len1, len2;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->texinfo = out;

-	loadmodel->numtexinfo = count;

-

-	for ( i=0 ; i<count ; i++, in++, out++)

-	{

-		for (j=0 ; j<8 ; j++)

-			out->vecs[0][j] = LittleFloat (in->vecs[0][j]);

-		len1 = Length (out->vecs[0]);

-		len2 = Length (out->vecs[1]);

-		len1 = (len1 + len2)/2;

-		if (len1 < 0.32)

-			out->mipadjust = 4;

-		else if (len1 < 0.49)

-			out->mipadjust = 3;

-		else if (len1 < 0.99)

-			out->mipadjust = 2;

-		else

-			out->mipadjust = 1;

-#if 0

-		if (len1 + len2 < 0.001)

-			out->mipadjust = 1;		// don't crash

-		else

-			out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );

-#endif

-

-		miptex = LittleLong (in->miptex);

-		out->flags = LittleLong (in->flags);

-	

-		if (!loadmodel->textures)

-		{

-			out->texture = r_notexture_mip;	// checkerboard texture

-			out->flags = 0;

-		}

-		else

-		{

-			if (miptex >= loadmodel->numtextures)

-				Sys_Error ("miptex >= loadmodel->numtextures");

-			out->texture = loadmodel->textures[miptex];

-			if (!out->texture)

-			{

-				out->texture = r_notexture_mip; // texture not found

-				out->flags = 0;

-			}

-		}

-	}

-}

-

-/*

-================

-CalcSurfaceExtents

-

-Fills in s->texturemins[] and s->extents[]

-================

-*/

-void CalcSurfaceExtents (msurface_t *s)

-{

-	float	mins[2], maxs[2], val;

-	int		i,j, e;

-	mvertex_t	*v;

-	mtexinfo_t	*tex;

-	int		bmins[2], bmaxs[2];

-

-	mins[0] = mins[1] = 999999;

-	maxs[0] = maxs[1] = -99999;

-

-	tex = s->texinfo;

-	

-	for (i=0 ; i<s->numedges ; i++)

-	{

-		e = loadmodel->surfedges[s->firstedge+i];

-		if (e >= 0)

-			v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];

-		else

-			v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];

-		

-		for (j=0 ; j<2 ; j++)

-		{

-			val = v->position[0] * tex->vecs[j][0] + 

-				v->position[1] * tex->vecs[j][1] +

-				v->position[2] * tex->vecs[j][2] +

-				tex->vecs[j][3];

-			if (val < mins[j])

-				mins[j] = val;

-			if (val > maxs[j])

-				maxs[j] = val;

-		}

-	}

-

-	for (i=0 ; i<2 ; i++)

-	{	

-		bmins[i] = floor(mins[i]/16);

-		bmaxs[i] = ceil(maxs[i]/16);

-

-		s->texturemins[i] = bmins[i] * 16;

-		s->extents[i] = (bmaxs[i] - bmins[i]) * 16;

-		if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 256)

-			Sys_Error ("Bad surface extents");

-	}

-}

-

-

-/*

-=================

-Mod_LoadFaces

-=================

-*/

-void Mod_LoadFaces (lump_t *l)

-{

-	dface_t		*in;

-	msurface_t 	*out;

-	int			i, count, surfnum;

-	int			planenum, side;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->surfaces = out;

-	loadmodel->numsurfaces = count;

-

-	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)

-	{

-		out->firstedge = LittleLong(in->firstedge);

-		out->numedges = LittleShort(in->numedges);		

-		out->flags = 0;

-

-		planenum = LittleShort(in->planenum);

-		side = LittleShort(in->side);

-		if (side)

-			out->flags |= SURF_PLANEBACK;			

-

-		out->plane = loadmodel->planes + planenum;

-

-		out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);

-

-		CalcSurfaceExtents (out);

-				

-	// lighting info

-

-		for (i=0 ; i<MAXLIGHTMAPS ; i++)

-			out->styles[i] = in->styles[i];

-		i = LittleLong(in->lightofs);

-		if (i == -1)

-			out->samples = NULL;

-		else

-			out->samples = loadmodel->lightdata + i;

-		

-	// set the drawing flags flag

-		

-		if (!Q_strncmp(out->texinfo->texture->name,"sky",3))	// sky

-		{

-			out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);

-			continue;

-		}

-		

-		if (!Q_strncmp(out->texinfo->texture->name,"*",1))		// turbulent

-		{

-			out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);

-			for (i=0 ; i<2 ; i++)

-			{

-				out->extents[i] = 16384;

-				out->texturemins[i] = -8192;

-			}

-			continue;

-		}

-	}

-}

-

-

-/*

-=================

-Mod_SetParent

-=================

-*/

-void Mod_SetParent (mnode_t *node, mnode_t *parent)

-{

-	node->parent = parent;

-	if (node->contents < 0)

-		return;

-	Mod_SetParent (node->children[0], node);

-	Mod_SetParent (node->children[1], node);

-}

-

-/*

-=================

-Mod_LoadNodes

-=================

-*/

-void Mod_LoadNodes (lump_t *l)

-{

-	int			i, j, count, p;

-	dnode_t		*in;

-	mnode_t 	*out;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->nodes = out;

-	loadmodel->numnodes = count;

-

-	for ( i=0 ; i<count ; i++, in++, out++)

-	{

-		for (j=0 ; j<3 ; j++)

-		{

-			out->minmaxs[j] = LittleShort (in->mins[j]);

-			out->minmaxs[3+j] = LittleShort (in->maxs[j]);

-		}

-	

-		p = LittleLong(in->planenum);

-		out->plane = loadmodel->planes + p;

-

-		out->firstsurface = LittleShort (in->firstface);

-		out->numsurfaces = LittleShort (in->numfaces);

-		

-		for (j=0 ; j<2 ; j++)

-		{

-			p = LittleShort (in->children[j]);

-			if (p >= 0)

-				out->children[j] = loadmodel->nodes + p;

-			else

-				out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));

-		}

-	}

-	

-	Mod_SetParent (loadmodel->nodes, NULL);	// sets nodes and leafs

-}

-

-/*

-=================

-Mod_LoadLeafs

-=================

-*/

-void Mod_LoadLeafs (lump_t *l)

-{

-	dleaf_t 	*in;

-	mleaf_t 	*out;

-	int			i, j, count, p;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->leafs = out;

-	loadmodel->numleafs = count;

-

-	for ( i=0 ; i<count ; i++, in++, out++)

-	{

-		for (j=0 ; j<3 ; j++)

-		{

-			out->minmaxs[j] = LittleShort (in->mins[j]);

-			out->minmaxs[3+j] = LittleShort (in->maxs[j]);

-		}

-

-		p = LittleLong(in->contents);

-		out->contents = p;

-

-		out->firstmarksurface = loadmodel->marksurfaces +

-			LittleShort(in->firstmarksurface);

-		out->nummarksurfaces = LittleShort(in->nummarksurfaces);

-		

-		p = LittleLong(in->visofs);

-		if (p == -1)

-			out->compressed_vis = NULL;

-		else

-			out->compressed_vis = loadmodel->visdata + p;

-		out->efrags = NULL;

-		

-		for (j=0 ; j<4 ; j++)

-			out->ambient_sound_level[j] = in->ambient_level[j];

-	}	

-}

-

-/*

-=================

-Mod_LoadClipnodes

-=================

-*/

-void Mod_LoadClipnodes (lump_t *l)

-{

-	dclipnode_t *in, *out;

-	int			i, count;

-	hull_t		*hull;

-

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->clipnodes = out;

-	loadmodel->numclipnodes = count;

-

-	hull = &loadmodel->hulls[1];

-	hull->clipnodes = out;

-	hull->firstclipnode = 0;

-	hull->lastclipnode = count-1;

-	hull->planes = loadmodel->planes;

-	hull->clip_mins[0] = -16;

-	hull->clip_mins[1] = -16;

-	hull->clip_mins[2] = -24;

-	hull->clip_maxs[0] = 16;

-	hull->clip_maxs[1] = 16;

-	hull->clip_maxs[2] = 32;

-

-	hull = &loadmodel->hulls[2];

-	hull->clipnodes = out;

-	hull->firstclipnode = 0;

-	hull->lastclipnode = count-1;

-	hull->planes = loadmodel->planes;

-	hull->clip_mins[0] = -32;

-	hull->clip_mins[1] = -32;

-	hull->clip_mins[2] = -24;

-	hull->clip_maxs[0] = 32;

-	hull->clip_maxs[1] = 32;

-	hull->clip_maxs[2] = 64;

-

-	for (i=0 ; i<count ; i++, out++, in++)

-	{

-		out->planenum = LittleLong(in->planenum);

-		out->children[0] = LittleShort(in->children[0]);

-		out->children[1] = LittleShort(in->children[1]);

-	}

-}

-

-/*

-=================

-Mod_MakeHull0

-

-Deplicate the drawing hull structure as a clipping hull

-=================

-*/

-void Mod_MakeHull0 (void)

-{

-	mnode_t		*in, *child;

-	dclipnode_t *out;

-	int			i, j, count;

-	hull_t		*hull;

-	

-	hull = &loadmodel->hulls[0];	

-	

-	in = loadmodel->nodes;

-	count = loadmodel->numnodes;

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	hull->clipnodes = out;

-	hull->firstclipnode = 0;

-	hull->lastclipnode = count-1;

-	hull->planes = loadmodel->planes;

-

-	for (i=0 ; i<count ; i++, out++, in++)

-	{

-		out->planenum = in->plane - loadmodel->planes;

-		for (j=0 ; j<2 ; j++)

-		{

-			child = in->children[j];

-			if (child->contents < 0)

-				out->children[j] = child->contents;

-			else

-				out->children[j] = child - loadmodel->nodes;

-		}

-	}

-}

-

-/*

-=================

-Mod_LoadMarksurfaces

-=================

-*/

-void Mod_LoadMarksurfaces (lump_t *l)

-{	

-	int		i, j, count;

-	short		*in;

-	msurface_t **out;

-	

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->marksurfaces = out;

-	loadmodel->nummarksurfaces = count;

-

-	for ( i=0 ; i<count ; i++)

-	{

-		j = LittleShort(in[i]);

-		if (j >= loadmodel->numsurfaces)

-			Sys_Error ("Mod_ParseMarksurfaces: bad surface number");

-		out[i] = loadmodel->surfaces + j;

-	}

-}

-

-/*

-=================

-Mod_LoadSurfedges

-=================

-*/

-void Mod_LoadSurfedges (lump_t *l)

-{	

-	int		i, count;

-	int		*in, *out;

-	

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*sizeof(*out), loadname);	

-

-	loadmodel->surfedges = out;

-	loadmodel->numsurfedges = count;

-

-	for ( i=0 ; i<count ; i++)

-		out[i] = LittleLong (in[i]);

-}

-

-/*

-=================

-Mod_LoadPlanes

-=================

-*/

-void Mod_LoadPlanes (lump_t *l)

-{

-	int			i, j;

-	mplane_t	*out;

-	dplane_t 	*in;

-	int			count;

-	int			bits;

-	

-	in = (void *)(mod_base + l->fileofs);

-	if (l->filelen % sizeof(*in))

-		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);

-	count = l->filelen / sizeof(*in);

-	out = Hunk_AllocName ( count*2*sizeof(*out), loadname);	

-	

-	loadmodel->planes = out;

-	loadmodel->numplanes = count;

-

-	for ( i=0 ; i<count ; i++, in++, out++)

-	{

-		bits = 0;

-		for (j=0 ; j<3 ; j++)

-		{

-			out->normal[j] = LittleFloat (in->normal[j]);

-			if (out->normal[j] < 0)

-				bits |= 1<<j;

-		}

-

-		out->dist = LittleFloat (in->dist);

-		out->type = LittleLong (in->type);

-		out->signbits = bits;

-	}

-}

-

-/*

-=================

-RadiusFromBounds

-=================

-*/

-float RadiusFromBounds (vec3_t mins, vec3_t maxs)

-{

-	int		i;

-	vec3_t	corner;

-

-	for (i=0 ; i<3 ; i++)

-	{

-		corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);

-	}

-

-	return Length (corner);

-}

-

-/*

-=================

-Mod_LoadBrushModel

-=================

-*/

-void Mod_LoadBrushModel (model_t *mod, void *buffer)

-{

-	int			i, j;

-	dheader_t	*header;

-	dmodel_t 	*bm;

-	

-	loadmodel->type = mod_brush;

-	

-	header = (dheader_t *)buffer;

-

-	i = LittleLong (header->version);

-	if (i != BSPVERSION)

-		Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);

-

-// swap all the lumps

-	mod_base = (byte *)header;

-

-	for (i=0 ; i<sizeof(dheader_t)/4 ; i++)

-		((int *)header)[i] = LittleLong ( ((int *)header)[i]);

-

-// load into heap

-	

-	Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);

-	Mod_LoadEdges (&header->lumps[LUMP_EDGES]);

-	Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);

-	Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);

-	Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);

-	Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);

-	Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);

-	Mod_LoadFaces (&header->lumps[LUMP_FACES]);

-	Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);

-	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);

-	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);

-	Mod_LoadNodes (&header->lumps[LUMP_NODES]);

-	Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);

-	Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);

-	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);

-

-	Mod_MakeHull0 ();

-	

-	mod->numframes = 2;		// regular and alternate animation

-	mod->flags = 0;

-	

-//

-// set up the submodels (FIXME: this is confusing)

-//

-	for (i=0 ; i<mod->numsubmodels ; i++)

-	{

-		bm = &mod->submodels[i];

-

-		mod->hulls[0].firstclipnode = bm->headnode[0];

-		for (j=1 ; j<MAX_MAP_HULLS ; j++)

-		{

-			mod->hulls[j].firstclipnode = bm->headnode[j];

-			mod->hulls[j].lastclipnode = mod->numclipnodes-1;

-		}

-		

-		mod->firstmodelsurface = bm->firstface;

-		mod->nummodelsurfaces = bm->numfaces;

-		

-		VectorCopy (bm->maxs, mod->maxs);

-		VectorCopy (bm->mins, mod->mins);

-		mod->radius = RadiusFromBounds (mod->mins, mod->maxs);

-		

-		mod->numleafs = bm->visleafs;

-

-		if (i < mod->numsubmodels-1)

-		{	// duplicate the basic information

-			char	name[10];

-

-			sprintf (name, "*%i", i+1);

-			loadmodel = Mod_FindName (name);

-			*loadmodel = *mod;

-			strcpy (loadmodel->name, name);

-			mod = loadmodel;

-		}

-	}

-}

-

-/*

-==============================================================================

-

-ALIAS MODELS

-

-==============================================================================

-*/

-

-/*

-=================

-Mod_LoadAliasFrame

-=================

-*/

-void * Mod_LoadAliasFrame (void * pin, int *pframeindex, int numv,

-	trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)

-{

-	trivertx_t		*pframe, *pinframe;

-	int				i, j;

-	daliasframe_t	*pdaliasframe;

-

-	pdaliasframe = (daliasframe_t *)pin;

-

-	strcpy (name, pdaliasframe->name);

-

-	for (i=0 ; i<3 ; i++)

-	{

-	// these are byte values, so we don't have to worry about

-	// endianness

-		pbboxmin->v[i] = pdaliasframe->bboxmin.v[i];

-		pbboxmax->v[i] = pdaliasframe->bboxmax.v[i];

-	}

-

-	pinframe = (trivertx_t *)(pdaliasframe + 1);

-	pframe = Hunk_AllocName (numv * sizeof(*pframe), loadname);

-

-	*pframeindex = (byte *)pframe - (byte *)pheader;

-

-	for (j=0 ; j<numv ; j++)

-	{

-		int		k;

-

-	// these are all byte values, so no need to deal with endianness

-		pframe[j].lightnormalindex = pinframe[j].lightnormalindex;

-

-		for (k=0 ; k<3 ; k++)

-		{

-			pframe[j].v[k] = pinframe[j].v[k];

-		}

-	}

-

-	pinframe += numv;

-

-	return (void *)pinframe;

-}

-

-

-/*

-=================

-Mod_LoadAliasGroup

-=================

-*/

-void * Mod_LoadAliasGroup (void * pin, int *pframeindex, int numv,

-	trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)

-{

-	daliasgroup_t		*pingroup;

-	maliasgroup_t		*paliasgroup;

-	int					i, numframes;

-	daliasinterval_t	*pin_intervals;

-	float				*poutintervals;

-	void				*ptemp;

-	

-	pingroup = (daliasgroup_t *)pin;

-

-	numframes = LittleLong (pingroup->numframes);

-

-	paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) +

-			(numframes - 1) * sizeof (paliasgroup->frames[0]), loadname);

-

-	paliasgroup->numframes = numframes;

-

-	for (i=0 ; i<3 ; i++)

-	{

-	// these are byte values, so we don't have to worry about endianness

-		pbboxmin->v[i] = pingroup->bboxmin.v[i];

-		pbboxmax->v[i] = pingroup->bboxmax.v[i];

-	}

-

-	*pframeindex = (byte *)paliasgroup - (byte *)pheader;

-

-	pin_intervals = (daliasinterval_t *)(pingroup + 1);

-

-	poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);

-

-	paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader;

-

-	for (i=0 ; i<numframes ; i++)

-	{

-		*poutintervals = LittleFloat (pin_intervals->interval);

-		if (*poutintervals <= 0.0)

-			Sys_Error ("Mod_LoadAliasGroup: interval<=0");

-

-		poutintervals++;

-		pin_intervals++;

-	}

-

-	ptemp = (void *)pin_intervals;

-

-	for (i=0 ; i<numframes ; i++)

-	{

-		ptemp = Mod_LoadAliasFrame (ptemp,

-									&paliasgroup->frames[i].frame,

-									numv,

-									&paliasgroup->frames[i].bboxmin,

-									&paliasgroup->frames[i].bboxmax,

-									pheader, name);

-	}

-

-	return ptemp;

-}

-

-

-/*

-=================

-Mod_LoadAliasSkin

-=================

-*/

-void * Mod_LoadAliasSkin (void * pin, int *pskinindex, int skinsize,

-	aliashdr_t *pheader)

-{

-	int		i;

-	byte	*pskin, *pinskin;

-	unsigned short	*pusskin;

-

-	pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname);

-	pinskin = (byte *)pin;

-	*pskinindex = (byte *)pskin - (byte *)pheader;

-

-	if (r_pixbytes == 1)

-	{

-		Q_memcpy (pskin, pinskin, skinsize);

-	}

-	else if (r_pixbytes == 2)

-	{

-		pusskin = (unsigned short *)pskin;

-

-		for (i=0 ; i<skinsize ; i++)

-			pusskin[i] = d_8to16table[pinskin[i]];

-	}

-	else

-	{

-		Sys_Error ("Mod_LoadAliasSkin: driver set invalid r_pixbytes: %d\n",

-				 r_pixbytes);

-	}

-

-	pinskin += skinsize;

-

-	return ((void *)pinskin);

-}

-

-

-/*

-=================

-Mod_LoadAliasSkinGroup

-=================

-*/

-void * Mod_LoadAliasSkinGroup (void * pin, int *pskinindex, int skinsize,

-	aliashdr_t *pheader)

-{

-	daliasskingroup_t		*pinskingroup;

-	maliasskingroup_t		*paliasskingroup;

-	int						i, numskins;

-	daliasskininterval_t	*pinskinintervals;

-	float					*poutskinintervals;

-	void					*ptemp;

-

-	pinskingroup = (daliasskingroup_t *)pin;

-

-	numskins = LittleLong (pinskingroup->numskins);

-

-	paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) +

-			(numskins - 1) * sizeof (paliasskingroup->skindescs[0]),

-			loadname);

-

-	paliasskingroup->numskins = numskins;

-

-	*pskinindex = (byte *)paliasskingroup - (byte *)pheader;

-

-	pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);

-

-	poutskinintervals = Hunk_AllocName (numskins * sizeof (float),loadname);

-

-	paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader;

-

-	for (i=0 ; i<numskins ; i++)

-	{

-		*poutskinintervals = LittleFloat (pinskinintervals->interval);

-		if (*poutskinintervals <= 0)

-			Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0");

-

-		poutskinintervals++;

-		pinskinintervals++;

-	}

-

-	ptemp = (void *)pinskinintervals;

-

-	for (i=0 ; i<numskins ; i++)

-	{

-		ptemp = Mod_LoadAliasSkin (ptemp,

-				&paliasskingroup->skindescs[i].skin, skinsize, pheader);

-	}

-

-	return ptemp;

-}

-

-

-/*

-=================

-Mod_LoadAliasModel

-=================

-*/

-void Mod_LoadAliasModel (model_t *mod, void *buffer)

-{

-	int					i;

-	mdl_t				*pmodel, *pinmodel;

-	stvert_t			*pstverts, *pinstverts;

-	aliashdr_t			*pheader;

-	mtriangle_t			*ptri;

-	dtriangle_t			*pintriangles;

-	int					version, numframes, numskins;

-	int					size;

-	daliasframetype_t	*pframetype;

-	daliasskintype_t	*pskintype;

-	maliasskindesc_t	*pskindesc;

-	int					skinsize;

-	int					start, end, total;

-	

-	start = Hunk_LowMark ();

-

-	pinmodel = (mdl_t *)buffer;

-

-	version = LittleLong (pinmodel->version);

-	if (version != ALIAS_VERSION)

-		Sys_Error ("%s has wrong version number (%i should be %i)",

-				 mod->name, version, ALIAS_VERSION);

-

-//

-// allocate space for a working header, plus all the data except the frames,

-// skin and group info

-//

-	size = 	sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) *

-			 sizeof (pheader->frames[0]) +

-			sizeof (mdl_t) +

-			LittleLong (pinmodel->numverts) * sizeof (stvert_t) +

-			LittleLong (pinmodel->numtris) * sizeof (mtriangle_t);

-

-	pheader = Hunk_AllocName (size, loadname);

-	pmodel = (mdl_t *) ((byte *)&pheader[1] +

-			(LittleLong (pinmodel->numframes) - 1) *

-			 sizeof (pheader->frames[0]));

-	

-//	mod->cache.data = pheader;

-	mod->flags = LittleLong (pinmodel->flags);

-

-//

-// endian-adjust and copy the data, starting with the alias model header

-//

-	pmodel->boundingradius = LittleFloat (pinmodel->boundingradius);

-	pmodel->numskins = LittleLong (pinmodel->numskins);

-	pmodel->skinwidth = LittleLong (pinmodel->skinwidth);

-	pmodel->skinheight = LittleLong (pinmodel->skinheight);

-

-	if (pmodel->skinheight > MAX_LBM_HEIGHT)

-		Sys_Error ("model %s has a skin taller than %d", mod->name,

-				   MAX_LBM_HEIGHT);

-

-	pmodel->numverts = LittleLong (pinmodel->numverts);

-

-	if (pmodel->numverts <= 0)

-		Sys_Error ("model %s has no vertices", mod->name);

-

-	if (pmodel->numverts > MAXALIASVERTS)

-		Sys_Error ("model %s has too many vertices", mod->name);

-

-	pmodel->numtris = LittleLong (pinmodel->numtris);

-

-	if (pmodel->numtris <= 0)

-		Sys_Error ("model %s has no triangles", mod->name);

-

-	pmodel->numframes = LittleLong (pinmodel->numframes);

-	pmodel->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;

-	mod->synctype = LittleLong (pinmodel->synctype);

-	mod->numframes = pmodel->numframes;

-

-	for (i=0 ; i<3 ; i++)

-	{

-		pmodel->scale[i] = LittleFloat (pinmodel->scale[i]);

-		pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);

-		pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);

-	}

-

-	numskins = pmodel->numskins;

-	numframes = pmodel->numframes;

-

-	if (pmodel->skinwidth & 0x03)

-		Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4");

-

-	pheader->model = (byte *)pmodel - (byte *)pheader;

-

-//

-// load the skins

-//

-	skinsize = pmodel->skinheight * pmodel->skinwidth;

-

-	if (numskins < 1)

-		Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);

-

-	pskintype = (daliasskintype_t *)&pinmodel[1];

-

-	pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),

-								loadname);

-

-	pheader->skindesc = (byte *)pskindesc - (byte *)pheader;

-

-	for (i=0 ; i<numskins ; i++)

-	{

-		aliasskintype_t	skintype;

-

-		skintype = LittleLong (pskintype->type);

-		pskindesc[i].type = skintype;

-

-		if (skintype == ALIAS_SKIN_SINGLE)

-		{

-			pskintype = (daliasskintype_t *)

-					Mod_LoadAliasSkin (pskintype + 1,

-									   &pskindesc[i].skin,

-									   skinsize, pheader);

-		}

-		else

-		{

-			pskintype = (daliasskintype_t *)

-					Mod_LoadAliasSkinGroup (pskintype + 1,

-											&pskindesc[i].skin,

-											skinsize, pheader);

-		}

-	}

-

-//

-// set base s and t vertices

-//

-	pstverts = (stvert_t *)&pmodel[1];

-	pinstverts = (stvert_t *)pskintype;

-

-	pheader->stverts = (byte *)pstverts - (byte *)pheader;

-

-	for (i=0 ; i<pmodel->numverts ; i++)

-	{

-		pstverts[i].onseam = LittleLong (pinstverts[i].onseam);

-	// put s and t in 16.16 format

-		pstverts[i].s = LittleLong (pinstverts[i].s) << 16;

-		pstverts[i].t = LittleLong (pinstverts[i].t) << 16;

-	}

-

-//

-// set up the triangles

-//

-	ptri = (mtriangle_t *)&pstverts[pmodel->numverts];

-	pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts];

-

-	pheader->triangles = (byte *)ptri - (byte *)pheader;

-

-	for (i=0 ; i<pmodel->numtris ; i++)

-	{

-		int		j;

-

-		ptri[i].facesfront = LittleLong (pintriangles[i].facesfront);

-

-		for (j=0 ; j<3 ; j++)

-		{

-			ptri[i].vertindex[j] =

-					LittleLong (pintriangles[i].vertindex[j]);

-		}

-	}

-

-//

-// load the frames

-//

-	if (numframes < 1)

-		Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);

-

-	pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris];

-

-	for (i=0 ; i<numframes ; i++)

-	{

-		aliasframetype_t	frametype;

-

-		frametype = LittleLong (pframetype->type);

-		pheader->frames[i].type = frametype;

-

-		if (frametype == ALIAS_SINGLE)

-		{

-			pframetype = (daliasframetype_t *)

-					Mod_LoadAliasFrame (pframetype + 1,

-										&pheader->frames[i].frame,

-										pmodel->numverts,

-										&pheader->frames[i].bboxmin,

-										&pheader->frames[i].bboxmax,

-										pheader, pheader->frames[i].name);

-		}

-		else

-		{

-			pframetype = (daliasframetype_t *)

-					Mod_LoadAliasGroup (pframetype + 1,

-										&pheader->frames[i].frame,

-										pmodel->numverts,

-										&pheader->frames[i].bboxmin,

-										&pheader->frames[i].bboxmax,

-										pheader, pheader->frames[i].name);

-		}

-	}

-

-	mod->type = mod_alias;

-

-// FIXME: do this right

-	mod->mins[0] = mod->mins[1] = mod->mins[2] = -16;

-	mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16;

-

-//

-// move the complete, relocatable alias model to the cache

-//	

-	end = Hunk_LowMark ();

-	total = end - start;

-	

-	Cache_Alloc (&mod->cache, total, loadname);

-	if (!mod->cache.data)

-		return;

-	memcpy (mod->cache.data, pheader, total);

-

-	Hunk_FreeToLowMark (start);

-}

-

-//=============================================================================

-

-/*

-=================

-Mod_LoadSpriteFrame

-=================

-*/

-void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe)

-{

-	dspriteframe_t		*pinframe;

-	mspriteframe_t		*pspriteframe;

-	int					i, width, height, size, origin[2];

-	unsigned short		*ppixout;

-	byte				*ppixin;

-

-	pinframe = (dspriteframe_t *)pin;

-

-	width = LittleLong (pinframe->width);

-	height = LittleLong (pinframe->height);

-	size = width * height;

-

-	pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size*r_pixbytes,

-								   loadname);

-

-	Q_memset (pspriteframe, 0, sizeof (mspriteframe_t) + size);

-	*ppframe = pspriteframe;

-

-	pspriteframe->width = width;

-	pspriteframe->height = height;

-	origin[0] = LittleLong (pinframe->origin[0]);

-	origin[1] = LittleLong (pinframe->origin[1]);

-

-	pspriteframe->up = origin[1];

-	pspriteframe->down = origin[1] - height;

-	pspriteframe->left = origin[0];

-	pspriteframe->right = width + origin[0];

-

-	if (r_pixbytes == 1)

-	{

-		Q_memcpy (&pspriteframe->pixels[0], (byte *)(pinframe + 1), size);

-	}

-	else if (r_pixbytes == 2)

-	{

-		ppixin = (byte *)(pinframe + 1);

-		ppixout = (unsigned short *)&pspriteframe->pixels[0];

-

-		for (i=0 ; i<size ; i++)

-			ppixout[i] = d_8to16table[ppixin[i]];

-	}

-	else

-	{

-		Sys_Error ("Mod_LoadSpriteFrame: driver set invalid r_pixbytes: %d\n",

-				 r_pixbytes);

-	}

-

-	return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);

-}

-

-

-/*

-=================

-Mod_LoadSpriteGroup

-=================

-*/

-void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe)

-{

-	dspritegroup_t		*pingroup;

-	mspritegroup_t		*pspritegroup;

-	int					i, numframes;

-	dspriteinterval_t	*pin_intervals;

-	float				*poutintervals;

-	void				*ptemp;

-

-	pingroup = (dspritegroup_t *)pin;

-

-	numframes = LittleLong (pingroup->numframes);

-

-	pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +

-				(numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);

-

-	pspritegroup->numframes = numframes;

-

-	*ppframe = (mspriteframe_t *)pspritegroup;

-

-	pin_intervals = (dspriteinterval_t *)(pingroup + 1);

-

-	poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);

-

-	pspritegroup->intervals = poutintervals;

-

-	for (i=0 ; i<numframes ; i++)

-	{

-		*poutintervals = LittleFloat (pin_intervals->interval);

-		if (*poutintervals <= 0.0)

-			Sys_Error ("Mod_LoadSpriteGroup: interval<=0");

-

-		poutintervals++;

-		pin_intervals++;

-	}

-

-	ptemp = (void *)pin_intervals;

-

-	for (i=0 ; i<numframes ; i++)

-	{

-		ptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i]);

-	}

-

-	return ptemp;

-}

-

-

-/*

-=================

-Mod_LoadSpriteModel

-=================

-*/

-void Mod_LoadSpriteModel (model_t *mod, void *buffer)

-{

-	int					i;

-	int					version;

-	dsprite_t			*pin;

-	msprite_t			*psprite;

-	int					numframes;

-	int					size;

-	dspriteframetype_t	*pframetype;

-	

-	pin = (dsprite_t *)buffer;

-

-	version = LittleLong (pin->version);

-	if (version != SPRITE_VERSION)

-		Sys_Error ("%s has wrong version number "

-				 "(%i should be %i)", mod->name, version, SPRITE_VERSION);

-

-	numframes = LittleLong (pin->numframes);

-

-	size = sizeof (msprite_t) +	(numframes - 1) * sizeof (psprite->frames);

-

-	psprite = Hunk_AllocName (size, loadname);

-

-	mod->cache.data = psprite;

-

-	psprite->type = LittleLong (pin->type);

-	psprite->maxwidth = LittleLong (pin->width);

-	psprite->maxheight = LittleLong (pin->height);

-	psprite->beamlength = LittleFloat (pin->beamlength);

-	mod->synctype = LittleLong (pin->synctype);

-	psprite->numframes = numframes;

-

-	mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;

-	mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2;

-	mod->mins[2] = -psprite->maxheight/2;

-	mod->maxs[2] = psprite->maxheight/2;

-	

-//

-// load the frames

-//

-	if (numframes < 1)

-		Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes);

-

-	mod->numframes = numframes;

-	mod->flags = 0;

-

-	pframetype = (dspriteframetype_t *)(pin + 1);

-

-	for (i=0 ; i<numframes ; i++)

-	{

-		spriteframetype_t	frametype;

-

-		frametype = LittleLong (pframetype->type);

-		psprite->frames[i].type = frametype;

-

-		if (frametype == SPR_SINGLE)

-		{

-			pframetype = (dspriteframetype_t *)

-					Mod_LoadSpriteFrame (pframetype + 1,

-										 &psprite->frames[i].frameptr);

-		}

-		else

-		{

-			pframetype = (dspriteframetype_t *)

-					Mod_LoadSpriteGroup (pframetype + 1,

-										 &psprite->frames[i].frameptr);

-		}

-	}

-

-	mod->type = mod_sprite;

-}

-

-//=============================================================================

-

-/*

-================

-Mod_Print

-================

-*/

-void Mod_Print (void)

-{

-	int		i;

-	model_t	*mod;

-

-	Con_Printf ("Cached models:\n");

-	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)

-	{

-		Con_Printf ("%8p : %s",mod->cache.data, mod->name);

-		if (mod->needload & NL_UNREFERENCED)

-			Con_Printf (" (!R)");

-		if (mod->needload & NL_NEEDS_LOADED)

-			Con_Printf (" (!P)");

-		Con_Printf ("\n");

-	}

-}

-

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// models.c -- model loading and caching
+
+// models are the only shared resource between a client and server running
+// on the same machine.
+
+#include "quakedef.h"
+#include "r_local.h"
+
+model_t	*loadmodel;
+char	loadname[32];	// for hunk tags
+
+void Mod_LoadSpriteModel (model_t *mod, void *buffer);
+void Mod_LoadBrushModel (model_t *mod, void *buffer);
+void Mod_LoadAliasModel (model_t *mod, void *buffer);
+model_t *Mod_LoadModel (model_t *mod, qboolean crash);
+
+byte	mod_novis[MAX_MAP_LEAFS/8];
+
+#define	MAX_MOD_KNOWN	256
+model_t	mod_known[MAX_MOD_KNOWN];
+int		mod_numknown;
+
+// values for model_t's needload
+#define NL_PRESENT		0
+#define NL_NEEDS_LOADED	1
+#define NL_UNREFERENCED	2
+
+/*
+===============
+Mod_Init
+===============
+*/
+void Mod_Init (void)
+{
+	memset (mod_novis, 0xff, sizeof(mod_novis));
+}
+
+/*
+===============
+Mod_Extradata
+
+Caches the data if needed
+===============
+*/
+void *Mod_Extradata (model_t *mod)
+{
+	void	*r;
+	
+	r = Cache_Check (&mod->cache);
+	if (r)
+		return r;
+
+	Mod_LoadModel (mod, true);
+	
+	if (!mod->cache.data)
+		Sys_Error ("Mod_Extradata: caching failed");
+	return mod->cache.data;
+}
+
+/*
+===============
+Mod_PointInLeaf
+===============
+*/
+mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
+{
+	mnode_t		*node;
+	float		d;
+	mplane_t	*plane;
+	
+	if (!model || !model->nodes)
+		Sys_Error ("Mod_PointInLeaf: bad model");
+
+	node = model->nodes;
+	while (1)
+	{
+		if (node->contents < 0)
+			return (mleaf_t *)node;
+		plane = node->plane;
+		d = DotProduct (p,plane->normal) - plane->dist;
+		if (d > 0)
+			node = node->children[0];
+		else
+			node = node->children[1];
+	}
+	
+	return NULL;	// never reached
+}
+
+
+/*
+===================
+Mod_DecompressVis
+===================
+*/
+byte *Mod_DecompressVis (byte *in, model_t *model)
+{
+	static byte	decompressed[MAX_MAP_LEAFS/8];
+	int		c;
+	byte	*out;
+	int		row;
+
+	row = (model->numleafs+7)>>3;	
+	out = decompressed;
+
+	if (!in)
+	{	// no vis info, so make all visible
+		while (row)
+		{
+			*out++ = 0xff;
+			row--;
+		}
+		return decompressed;		
+	}
+
+	do
+	{
+		if (*in)
+		{
+			*out++ = *in++;
+			continue;
+		}
+	
+		c = in[1];
+		in += 2;
+		while (c)
+		{
+			*out++ = 0;
+			c--;
+		}
+	} while (out - decompressed < row);
+	
+	return decompressed;
+}
+
+byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
+{
+	if (leaf == model->leafs)
+		return mod_novis;
+	return Mod_DecompressVis (leaf->compressed_vis, model);
+}
+
+/*
+===================
+Mod_ClearAll
+===================
+*/
+void Mod_ClearAll (void)
+{
+	int		i;
+	model_t	*mod;
+
+
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) {
+		mod->needload = NL_UNREFERENCED;
+//FIX FOR CACHE_ALLOC ERRORS:
+		if (mod->type == mod_sprite) mod->cache.data = NULL;
+	}
+}
+
+/*
+==================
+Mod_FindName
+
+==================
+*/
+model_t *Mod_FindName (char *name)
+{
+	int		i;
+	model_t	*mod;
+	model_t	*avail = NULL;
+
+	if (!name[0])
+		Sys_Error ("Mod_ForName: NULL name");
+		
+//
+// search the currently loaded models
+//
+	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+	{
+		if (!strcmp (mod->name, name) )
+			break;
+		if (mod->needload == NL_UNREFERENCED)
+			if (!avail || mod->type != mod_alias)
+				avail = mod;
+	}
+			
+	if (i == mod_numknown)
+	{
+		if (mod_numknown == MAX_MOD_KNOWN)
+		{
+			if (avail)
+			{
+				mod = avail;
+				if (mod->type == mod_alias)
+					if (Cache_Check (&mod->cache))
+						Cache_Free (&mod->cache);
+			}
+			else
+				Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
+		}
+		else
+			mod_numknown++;
+		strcpy (mod->name, name);
+		mod->needload = NL_NEEDS_LOADED;
+	}
+
+	return mod;
+}
+
+/*
+==================
+Mod_TouchModel
+
+==================
+*/
+void Mod_TouchModel (char *name)
+{
+	model_t	*mod;
+	
+	mod = Mod_FindName (name);
+	
+	if (mod->needload == NL_PRESENT)
+	{
+		if (mod->type == mod_alias)
+			Cache_Check (&mod->cache);
+	}
+}
+
+/*
+==================
+Mod_LoadModel
+
+Loads a model into the cache
+==================
+*/
+model_t *Mod_LoadModel (model_t *mod, qboolean crash)
+{
+	unsigned *buf;
+	byte	stackbuf[1024];		// avoid dirtying the cache heap
+
+	if (mod->type == mod_alias)
+	{
+		if (Cache_Check (&mod->cache))
+		{
+			mod->needload = NL_PRESENT;
+			return mod;
+		}
+	}
+	else
+	{
+		if (mod->needload == NL_PRESENT)
+			return mod;
+	}
+
+//
+// because the world is so huge, load it one piece at a time
+//
+	
+//
+// load the file
+//
+	buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf));
+	if (!buf)
+	{
+		if (crash)
+			Sys_Error ("Mod_NumForName: %s not found", mod->name);
+		return NULL;
+	}
+	
+//
+// allocate a new model
+//
+	COM_FileBase (mod->name, loadname, sizeof(loadname));
+	
+	loadmodel = mod;
+
+//
+// fill it in
+//
+
+// call the apropriate loader
+	mod->needload = NL_PRESENT;
+
+	switch (LittleLong(*(unsigned *)buf))
+	{
+	case IDPOLYHEADER:
+		Mod_LoadAliasModel (mod, buf);
+		break;
+		
+	case IDSPRITEHEADER:
+		Mod_LoadSpriteModel (mod, buf);
+		break;
+	
+	default:
+		Mod_LoadBrushModel (mod, buf);
+		break;
+	}
+
+	return mod;
+}
+
+/*
+==================
+Mod_ForName
+
+Loads in a model for the given name
+==================
+*/
+model_t *Mod_ForName (char *name, qboolean crash)
+{
+	model_t	*mod;
+
+	mod = Mod_FindName (name);
+
+	return Mod_LoadModel (mod, crash);
+}
+
+
+/*
+===============================================================================
+
+					BRUSHMODEL LOADING
+
+===============================================================================
+*/
+
+byte	*mod_base;
+
+
+/*
+=================
+Mod_LoadTextures
+=================
+*/
+void Mod_LoadTextures (lump_t *l)
+{
+	int		i, j, pixels, num, max, altmax;
+	miptex_t	*mt;
+	texture_t	*tx, *tx2;
+	texture_t	*anims[10];
+	texture_t	*altanims[10];
+	dmiptexlump_t *m;
+
+	if (!l->filelen)
+	{
+		loadmodel->textures = NULL;
+		return;
+	}
+	m = (dmiptexlump_t *)(mod_base + l->fileofs);
+	
+	m->nummiptex = LittleLong (m->nummiptex);
+	
+	loadmodel->numtextures = m->nummiptex;
+	loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);
+
+	for (i=0 ; i<m->nummiptex ; i++)
+	{
+		m->dataofs[i] = LittleLong(m->dataofs[i]);
+		if (m->dataofs[i] == -1)
+			continue;
+		mt = (miptex_t *)((byte *)m + m->dataofs[i]);
+		mt->width = LittleLong (mt->width);
+		mt->height = LittleLong (mt->height);
+		for (j=0 ; j<MIPLEVELS ; j++)
+			mt->offsets[j] = LittleLong (mt->offsets[j]);
+		
+		if ( (mt->width & 15) || (mt->height & 15) )
+			Sys_Error ("Texture %s is not 16 aligned", mt->name);
+		pixels = mt->width*mt->height/64*85;
+		tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
+		loadmodel->textures[i] = tx;
+
+		memcpy (tx->name, mt->name, sizeof(tx->name));
+		tx->width = mt->width;
+		tx->height = mt->height;
+		for (j=0 ; j<MIPLEVELS ; j++)
+			tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);
+		// the pixels immediately follow the structures
+		memcpy ( tx+1, mt+1, pixels);
+		
+		if (!Q_strncmp(mt->name,"sky",3))	
+			R_InitSky (tx);
+	}
+
+//
+// sequence the animations
+//
+	for (i=0 ; i<m->nummiptex ; i++)
+	{
+		tx = loadmodel->textures[i];
+		if (!tx || tx->name[0] != '+')
+			continue;
+		if (tx->anim_next)
+			continue;	// allready sequenced
+
+	// find the number of frames in the animation
+		memset (anims, 0, sizeof(anims));
+		memset (altanims, 0, sizeof(altanims));
+
+		max = tx->name[1];
+		altmax = 0;
+		if (max >= 'a' && max <= 'z')
+			max -= 'a' - 'A';
+		if (max >= '0' && max <= '9')
+		{
+			max -= '0';
+			altmax = 0;
+			anims[max] = tx;
+			max++;
+		}
+		else if (max >= 'A' && max <= 'J')
+		{
+			altmax = max - 'A';
+			max = 0;
+			altanims[altmax] = tx;
+			altmax++;
+		}
+		else
+			Sys_Error ("Bad animating texture %s", tx->name);
+
+		for (j=i+1 ; j<m->nummiptex ; j++)
+		{
+			tx2 = loadmodel->textures[j];
+			if (!tx2 || tx2->name[0] != '+')
+				continue;
+			if (strcmp (tx2->name+2, tx->name+2))
+				continue;
+
+			num = tx2->name[1];
+			if (num >= 'a' && num <= 'z')
+				num -= 'a' - 'A';
+			if (num >= '0' && num <= '9')
+			{
+				num -= '0';
+				anims[num] = tx2;
+				if (num+1 > max)
+					max = num + 1;
+			}
+			else if (num >= 'A' && num <= 'J')
+			{
+				num = num - 'A';
+				altanims[num] = tx2;
+				if (num+1 > altmax)
+					altmax = num+1;
+			}
+			else
+				Sys_Error ("Bad animating texture %s", tx->name);
+		}
+		
+#define	ANIM_CYCLE	2
+	// link them all together
+		for (j=0 ; j<max ; j++)
+		{
+			tx2 = anims[j];
+			if (!tx2)
+				Sys_Error ("Missing frame %i of %s",j, tx->name);
+			tx2->anim_total = max * ANIM_CYCLE;
+			tx2->anim_min = j * ANIM_CYCLE;
+			tx2->anim_max = (j+1) * ANIM_CYCLE;
+			tx2->anim_next = anims[ (j+1)%max ];
+			if (altmax)
+				tx2->alternate_anims = altanims[0];
+		}
+		for (j=0 ; j<altmax ; j++)
+		{
+			tx2 = altanims[j];
+			if (!tx2)
+				Sys_Error ("Missing frame %i of %s",j, tx->name);
+			tx2->anim_total = altmax * ANIM_CYCLE;
+			tx2->anim_min = j * ANIM_CYCLE;
+			tx2->anim_max = (j+1) * ANIM_CYCLE;
+			tx2->anim_next = altanims[ (j+1)%altmax ];
+			if (max)
+				tx2->alternate_anims = anims[0];
+		}
+	}
+}
+
+/*
+=================
+Mod_LoadLighting
+=================
+*/
+void Mod_LoadLighting (lump_t *l)
+{
+	if (!l->filelen)
+	{
+		loadmodel->lightdata = NULL;
+		return;
+	}
+	loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);	
+	memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
+}
+
+
+/*
+=================
+Mod_LoadVisibility
+=================
+*/
+void Mod_LoadVisibility (lump_t *l)
+{
+	if (!l->filelen)
+	{
+		loadmodel->visdata = NULL;
+		return;
+	}
+	loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname);	
+	memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
+}
+
+
+/*
+=================
+Mod_LoadEntities
+=================
+*/
+void Mod_LoadEntities (lump_t *l)
+{
+	if (!l->filelen)
+	{
+		loadmodel->entities = NULL;
+		return;
+	}
+	loadmodel->entities = Hunk_AllocName ( l->filelen, loadname);	
+	memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
+}
+
+
+/*
+=================
+Mod_LoadVertexes
+=================
+*/
+void Mod_LoadVertexes (lump_t *l)
+{
+	dvertex_t	*in;
+	mvertex_t	*out;
+	int			i, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->vertexes = out;
+	loadmodel->numvertexes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->position[0] = LittleFloat (in->point[0]);
+		out->position[1] = LittleFloat (in->point[1]);
+		out->position[2] = LittleFloat (in->point[2]);
+	}
+}
+
+/*
+=================
+Mod_LoadSubmodels
+=================
+*/
+void Mod_LoadSubmodels (lump_t *l)
+{
+	dmodel_t	*in;
+	dmodel_t	*out;
+	int			i, j, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->submodels = out;
+	loadmodel->numsubmodels = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{	// spread the mins / maxs by a pixel
+			out->mins[j] = LittleFloat (in->mins[j]) - 1;
+			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
+			out->origin[j] = LittleFloat (in->origin[j]);
+		}
+		for (j=0 ; j<MAX_MAP_HULLS ; j++)
+			out->headnode[j] = LittleLong (in->headnode[j]);
+		out->visleafs = LittleLong (in->visleafs);
+		out->firstface = LittleLong (in->firstface);
+		out->numfaces = LittleLong (in->numfaces);
+	}
+}
+
+/*
+=================
+Mod_LoadEdges
+=================
+*/
+void Mod_LoadEdges (lump_t *l)
+{
+	dedge_t *in;
+	medge_t *out;
+	int 	i, count;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);	
+
+	loadmodel->edges = out;
+	loadmodel->numedges = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		out->v[0] = (unsigned short)LittleShort(in->v[0]);
+		out->v[1] = (unsigned short)LittleShort(in->v[1]);
+	}
+}
+
+/*
+=================
+Mod_LoadTexinfo
+=================
+*/
+void Mod_LoadTexinfo (lump_t *l)
+{
+	texinfo_t *in;
+	mtexinfo_t *out;
+	int 	i, j, count;
+	int		miptex;
+	float	len1, len2;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->texinfo = out;
+	loadmodel->numtexinfo = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		for (j=0 ; j<8 ; j++)
+			out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
+		len1 = Length (out->vecs[0]);
+		len2 = Length (out->vecs[1]);
+		len1 = (len1 + len2)/2;
+		if (len1 < 0.32)
+			out->mipadjust = 4;
+		else if (len1 < 0.49)
+			out->mipadjust = 3;
+		else if (len1 < 0.99)
+			out->mipadjust = 2;
+		else
+			out->mipadjust = 1;
+#if 0
+		if (len1 + len2 < 0.001)
+			out->mipadjust = 1;		// don't crash
+		else
+			out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
+#endif
+
+		miptex = LittleLong (in->miptex);
+		out->flags = LittleLong (in->flags);
+	
+		if (!loadmodel->textures)
+		{
+			out->texture = r_notexture_mip;	// checkerboard texture
+			out->flags = 0;
+		}
+		else
+		{
+			if (miptex >= loadmodel->numtextures)
+				Sys_Error ("miptex >= loadmodel->numtextures");
+			out->texture = loadmodel->textures[miptex];
+			if (!out->texture)
+			{
+				out->texture = r_notexture_mip; // texture not found
+				out->flags = 0;
+			}
+		}
+	}
+}
+
+/*
+================
+CalcSurfaceExtents
+
+Fills in s->texturemins[] and s->extents[]
+================
+*/
+void CalcSurfaceExtents (msurface_t *s)
+{
+	float	mins[2], maxs[2], val;
+	int		i,j, e;
+	mvertex_t	*v;
+	mtexinfo_t	*tex;
+	int		bmins[2], bmaxs[2];
+
+	mins[0] = mins[1] = 999999;
+	maxs[0] = maxs[1] = -99999;
+
+	tex = s->texinfo;
+	
+	for (i=0 ; i<s->numedges ; i++)
+	{
+		e = loadmodel->surfedges[s->firstedge+i];
+		if (e >= 0)
+			v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
+		else
+			v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
+		
+		for (j=0 ; j<2 ; j++)
+		{
+			val = v->position[0] * tex->vecs[j][0] + 
+				v->position[1] * tex->vecs[j][1] +
+				v->position[2] * tex->vecs[j][2] +
+				tex->vecs[j][3];
+			if (val < mins[j])
+				mins[j] = val;
+			if (val > maxs[j])
+				maxs[j] = val;
+		}
+	}
+
+	for (i=0 ; i<2 ; i++)
+	{	
+		bmins[i] = floor(mins[i]/16);
+		bmaxs[i] = ceil(maxs[i]/16);
+
+		s->texturemins[i] = bmins[i] * 16;
+		s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
+		if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 256)
+			Sys_Error ("Bad surface extents");
+	}
+}
+
+
+/*
+=================
+Mod_LoadFaces
+=================
+*/
+void Mod_LoadFaces (lump_t *l)
+{
+	dface_t		*in;
+	msurface_t 	*out;
+	int			i, count, surfnum;
+	int			planenum, side;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->surfaces = out;
+	loadmodel->numsurfaces = count;
+
+	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
+	{
+		out->firstedge = LittleLong(in->firstedge);
+		out->numedges = LittleShort(in->numedges);		
+		out->flags = 0;
+
+		planenum = LittleShort(in->planenum);
+		side = LittleShort(in->side);
+		if (side)
+			out->flags |= SURF_PLANEBACK;			
+
+		out->plane = loadmodel->planes + planenum;
+
+		out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
+
+		CalcSurfaceExtents (out);
+				
+	// lighting info
+
+		for (i=0 ; i<MAXLIGHTMAPS ; i++)
+			out->styles[i] = in->styles[i];
+		i = LittleLong(in->lightofs);
+		if (i == -1)
+			out->samples = NULL;
+		else
+			out->samples = loadmodel->lightdata + i;
+		
+	// set the drawing flags flag
+		
+		if (!Q_strncmp(out->texinfo->texture->name,"sky",3))	// sky
+		{
+			out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
+			continue;
+		}
+		
+		if (!Q_strncmp(out->texinfo->texture->name,"*",1))		// turbulent
+		{
+			out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
+			for (i=0 ; i<2 ; i++)
+			{
+				out->extents[i] = 16384;
+				out->texturemins[i] = -8192;
+			}
+			continue;
+		}
+	}
+}
+
+
+/*
+=================
+Mod_SetParent
+=================
+*/
+void Mod_SetParent (mnode_t *node, mnode_t *parent)
+{
+	node->parent = parent;
+	if (node->contents < 0)
+		return;
+	Mod_SetParent (node->children[0], node);
+	Mod_SetParent (node->children[1], node);
+}
+
+/*
+=================
+Mod_LoadNodes
+=================
+*/
+void Mod_LoadNodes (lump_t *l)
+{
+	int			i, j, count, p;
+	dnode_t		*in;
+	mnode_t 	*out;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->nodes = out;
+	loadmodel->numnodes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			out->minmaxs[j] = LittleShort (in->mins[j]);
+			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+		}
+	
+		p = LittleLong(in->planenum);
+		out->plane = loadmodel->planes + p;
+
+		out->firstsurface = LittleShort (in->firstface);
+		out->numsurfaces = LittleShort (in->numfaces);
+		
+		for (j=0 ; j<2 ; j++)
+		{
+			p = LittleShort (in->children[j]);
+			if (p >= 0)
+				out->children[j] = loadmodel->nodes + p;
+			else
+				out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
+		}
+	}
+	
+	Mod_SetParent (loadmodel->nodes, NULL);	// sets nodes and leafs
+}
+
+/*
+=================
+Mod_LoadLeafs
+=================
+*/
+void Mod_LoadLeafs (lump_t *l)
+{
+	dleaf_t 	*in;
+	mleaf_t 	*out;
+	int			i, j, count, p;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->leafs = out;
+	loadmodel->numleafs = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		for (j=0 ; j<3 ; j++)
+		{
+			out->minmaxs[j] = LittleShort (in->mins[j]);
+			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+		}
+
+		p = LittleLong(in->contents);
+		out->contents = p;
+
+		out->firstmarksurface = loadmodel->marksurfaces +
+			LittleShort(in->firstmarksurface);
+		out->nummarksurfaces = LittleShort(in->nummarksurfaces);
+		
+		p = LittleLong(in->visofs);
+		if (p == -1)
+			out->compressed_vis = NULL;
+		else
+			out->compressed_vis = loadmodel->visdata + p;
+		out->efrags = NULL;
+		
+		for (j=0 ; j<4 ; j++)
+			out->ambient_sound_level[j] = in->ambient_level[j];
+	}	
+}
+
+/*
+=================
+Mod_LoadClipnodes
+=================
+*/
+void Mod_LoadClipnodes (lump_t *l)
+{
+	dclipnode_t *in, *out;
+	int			i, count;
+	hull_t		*hull;
+
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->clipnodes = out;
+	loadmodel->numclipnodes = count;
+
+	hull = &loadmodel->hulls[1];
+	hull->clipnodes = out;
+	hull->firstclipnode = 0;
+	hull->lastclipnode = count-1;
+	hull->planes = loadmodel->planes;
+	hull->clip_mins[0] = -16;
+	hull->clip_mins[1] = -16;
+	hull->clip_mins[2] = -24;
+	hull->clip_maxs[0] = 16;
+	hull->clip_maxs[1] = 16;
+	hull->clip_maxs[2] = 32;
+
+	hull = &loadmodel->hulls[2];
+	hull->clipnodes = out;
+	hull->firstclipnode = 0;
+	hull->lastclipnode = count-1;
+	hull->planes = loadmodel->planes;
+	hull->clip_mins[0] = -32;
+	hull->clip_mins[1] = -32;
+	hull->clip_mins[2] = -24;
+	hull->clip_maxs[0] = 32;
+	hull->clip_maxs[1] = 32;
+	hull->clip_maxs[2] = 64;
+
+	for (i=0 ; i<count ; i++, out++, in++)
+	{
+		out->planenum = LittleLong(in->planenum);
+		out->children[0] = LittleShort(in->children[0]);
+		out->children[1] = LittleShort(in->children[1]);
+	}
+}
+
+/*
+=================
+Mod_MakeHull0
+
+Deplicate the drawing hull structure as a clipping hull
+=================
+*/
+void Mod_MakeHull0 (void)
+{
+	mnode_t		*in, *child;
+	dclipnode_t *out;
+	int			i, j, count;
+	hull_t		*hull;
+	
+	hull = &loadmodel->hulls[0];	
+	
+	in = loadmodel->nodes;
+	count = loadmodel->numnodes;
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	hull->clipnodes = out;
+	hull->firstclipnode = 0;
+	hull->lastclipnode = count-1;
+	hull->planes = loadmodel->planes;
+
+	for (i=0 ; i<count ; i++, out++, in++)
+	{
+		out->planenum = in->plane - loadmodel->planes;
+		for (j=0 ; j<2 ; j++)
+		{
+			child = in->children[j];
+			if (child->contents < 0)
+				out->children[j] = child->contents;
+			else
+				out->children[j] = child - loadmodel->nodes;
+		}
+	}
+}
+
+/*
+=================
+Mod_LoadMarksurfaces
+=================
+*/
+void Mod_LoadMarksurfaces (lump_t *l)
+{	
+	int		i, j, count;
+	short		*in;
+	msurface_t **out;
+	
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->marksurfaces = out;
+	loadmodel->nummarksurfaces = count;
+
+	for ( i=0 ; i<count ; i++)
+	{
+		j = LittleShort(in[i]);
+		if (j >= loadmodel->numsurfaces)
+			Sys_Error ("Mod_ParseMarksurfaces: bad surface number");
+		out[i] = loadmodel->surfaces + j;
+	}
+}
+
+/*
+=================
+Mod_LoadSurfedges
+=================
+*/
+void Mod_LoadSurfedges (lump_t *l)
+{	
+	int		i, count;
+	int		*in, *out;
+	
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*sizeof(*out), loadname);	
+
+	loadmodel->surfedges = out;
+	loadmodel->numsurfedges = count;
+
+	for ( i=0 ; i<count ; i++)
+		out[i] = LittleLong (in[i]);
+}
+
+/*
+=================
+Mod_LoadPlanes
+=================
+*/
+void Mod_LoadPlanes (lump_t *l)
+{
+	int			i, j;
+	mplane_t	*out;
+	dplane_t 	*in;
+	int			count;
+	int			bits;
+	
+	in = (void *)(mod_base + l->fileofs);
+	if (l->filelen % sizeof(*in))
+		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+	count = l->filelen / sizeof(*in);
+	out = Hunk_AllocName ( count*2*sizeof(*out), loadname);	
+	
+	loadmodel->planes = out;
+	loadmodel->numplanes = count;
+
+	for ( i=0 ; i<count ; i++, in++, out++)
+	{
+		bits = 0;
+		for (j=0 ; j<3 ; j++)
+		{
+			out->normal[j] = LittleFloat (in->normal[j]);
+			if (out->normal[j] < 0)
+				bits |= 1<<j;
+		}
+
+		out->dist = LittleFloat (in->dist);
+		out->type = LittleLong (in->type);
+		out->signbits = bits;
+	}
+}
+
+/*
+=================
+RadiusFromBounds
+=================
+*/
+float RadiusFromBounds (vec3_t mins, vec3_t maxs)
+{
+	int		i;
+	vec3_t	corner;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
+	}
+
+	return Length (corner);
+}
+
+/*
+=================
+Mod_LoadBrushModel
+=================
+*/
+void Mod_LoadBrushModel (model_t *mod, void *buffer)
+{
+	int			i, j;
+	dheader_t	*header;
+	dmodel_t 	*bm;
+	
+	loadmodel->type = mod_brush;
+	
+	header = (dheader_t *)buffer;
+
+	i = LittleLong (header->version);
+	if (i != BSPVERSION)
+		Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
+
+// swap all the lumps
+	mod_base = (byte *)header;
+
+	for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
+		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+// load into heap
+	
+	Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
+	Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
+	Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
+	Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
+	Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
+	Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
+	Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
+	Mod_LoadFaces (&header->lumps[LUMP_FACES]);
+	Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
+	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
+	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
+	Mod_LoadNodes (&header->lumps[LUMP_NODES]);
+	Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
+	Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
+	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+
+	Mod_MakeHull0 ();
+	
+	mod->numframes = 2;		// regular and alternate animation
+	mod->flags = 0;
+	
+//
+// set up the submodels (FIXME: this is confusing)
+//
+	for (i=0 ; i<mod->numsubmodels ; i++)
+	{
+		bm = &mod->submodels[i];
+
+		mod->hulls[0].firstclipnode = bm->headnode[0];
+		for (j=1 ; j<MAX_MAP_HULLS ; j++)
+		{
+			mod->hulls[j].firstclipnode = bm->headnode[j];
+			mod->hulls[j].lastclipnode = mod->numclipnodes-1;
+		}
+		
+		mod->firstmodelsurface = bm->firstface;
+		mod->nummodelsurfaces = bm->numfaces;
+		
+		VectorCopy (bm->maxs, mod->maxs);
+		VectorCopy (bm->mins, mod->mins);
+		mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
+		
+		mod->numleafs = bm->visleafs;
+
+		if (i < mod->numsubmodels-1)
+		{	// duplicate the basic information
+			char	name[10];
+
+			sprintf (name, "*%i", i+1);
+			loadmodel = Mod_FindName (name);
+			*loadmodel = *mod;
+			strcpy (loadmodel->name, name);
+			mod = loadmodel;
+		}
+	}
+}
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadAliasFrame
+=================
+*/
+void * Mod_LoadAliasFrame (void * pin, int *pframeindex, int numv,
+	trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
+{
+	trivertx_t		*pframe, *pinframe;
+	int				i, j;
+	daliasframe_t	*pdaliasframe;
+
+	pdaliasframe = (daliasframe_t *)pin;
+
+	strcpy (name, pdaliasframe->name);
+
+	for (i=0 ; i<3 ; i++)
+	{
+	// these are byte values, so we don't have to worry about
+	// endianness
+		pbboxmin->v[i] = pdaliasframe->bboxmin.v[i];
+		pbboxmax->v[i] = pdaliasframe->bboxmax.v[i];
+	}
+
+	pinframe = (trivertx_t *)(pdaliasframe + 1);
+	pframe = Hunk_AllocName (numv * sizeof(*pframe), loadname);
+
+	*pframeindex = (byte *)pframe - (byte *)pheader;
+
+	for (j=0 ; j<numv ; j++)
+	{
+		int		k;
+
+	// these are all byte values, so no need to deal with endianness
+		pframe[j].lightnormalindex = pinframe[j].lightnormalindex;
+
+		for (k=0 ; k<3 ; k++)
+		{
+			pframe[j].v[k] = pinframe[j].v[k];
+		}
+	}
+
+	pinframe += numv;
+
+	return (void *)pinframe;
+}
+
+
+/*
+=================
+Mod_LoadAliasGroup
+=================
+*/
+void * Mod_LoadAliasGroup (void * pin, int *pframeindex, int numv,
+	trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
+{
+	daliasgroup_t		*pingroup;
+	maliasgroup_t		*paliasgroup;
+	int					i, numframes;
+	daliasinterval_t	*pin_intervals;
+	float				*poutintervals;
+	void				*ptemp;
+	
+	pingroup = (daliasgroup_t *)pin;
+
+	numframes = LittleLong (pingroup->numframes);
+
+	paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) +
+			(numframes - 1) * sizeof (paliasgroup->frames[0]), loadname);
+
+	paliasgroup->numframes = numframes;
+
+	for (i=0 ; i<3 ; i++)
+	{
+	// these are byte values, so we don't have to worry about endianness
+		pbboxmin->v[i] = pingroup->bboxmin.v[i];
+		pbboxmax->v[i] = pingroup->bboxmax.v[i];
+	}
+
+	*pframeindex = (byte *)paliasgroup - (byte *)pheader;
+
+	pin_intervals = (daliasinterval_t *)(pingroup + 1);
+
+	poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
+
+	paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader;
+
+	for (i=0 ; i<numframes ; i++)
+	{
+		*poutintervals = LittleFloat (pin_intervals->interval);
+		if (*poutintervals <= 0.0)
+			Sys_Error ("Mod_LoadAliasGroup: interval<=0");
+
+		poutintervals++;
+		pin_intervals++;
+	}
+
+	ptemp = (void *)pin_intervals;
+
+	for (i=0 ; i<numframes ; i++)
+	{
+		ptemp = Mod_LoadAliasFrame (ptemp,
+									&paliasgroup->frames[i].frame,
+									numv,
+									&paliasgroup->frames[i].bboxmin,
+									&paliasgroup->frames[i].bboxmax,
+									pheader, name);
+	}
+
+	return ptemp;
+}
+
+
+/*
+=================
+Mod_LoadAliasSkin
+=================
+*/
+void * Mod_LoadAliasSkin (void * pin, int *pskinindex, int skinsize,
+	aliashdr_t *pheader)
+{
+	int		i;
+	byte	*pskin, *pinskin;
+	unsigned short	*pusskin;
+
+	pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname);
+	pinskin = (byte *)pin;
+	*pskinindex = (byte *)pskin - (byte *)pheader;
+
+	if (r_pixbytes == 1)
+	{
+		Q_memcpy (pskin, pinskin, skinsize);
+	}
+	else if (r_pixbytes == 2)
+	{
+		pusskin = (unsigned short *)pskin;
+
+		for (i=0 ; i<skinsize ; i++)
+			pusskin[i] = d_8to16table[pinskin[i]];
+	}
+	else
+	{
+		Sys_Error ("Mod_LoadAliasSkin: driver set invalid r_pixbytes: %d\n",
+				 r_pixbytes);
+	}
+
+	pinskin += skinsize;
+
+	return ((void *)pinskin);
+}
+
+
+/*
+=================
+Mod_LoadAliasSkinGroup
+=================
+*/
+void * Mod_LoadAliasSkinGroup (void * pin, int *pskinindex, int skinsize,
+	aliashdr_t *pheader)
+{
+	daliasskingroup_t		*pinskingroup;
+	maliasskingroup_t		*paliasskingroup;
+	int						i, numskins;
+	daliasskininterval_t	*pinskinintervals;
+	float					*poutskinintervals;
+	void					*ptemp;
+
+	pinskingroup = (daliasskingroup_t *)pin;
+
+	numskins = LittleLong (pinskingroup->numskins);
+
+	paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) +
+			(numskins - 1) * sizeof (paliasskingroup->skindescs[0]),
+			loadname);
+
+	paliasskingroup->numskins = numskins;
+
+	*pskinindex = (byte *)paliasskingroup - (byte *)pheader;
+
+	pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
+
+	poutskinintervals = Hunk_AllocName (numskins * sizeof (float),loadname);
+
+	paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader;
+
+	for (i=0 ; i<numskins ; i++)
+	{
+		*poutskinintervals = LittleFloat (pinskinintervals->interval);
+		if (*poutskinintervals <= 0)
+			Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0");
+
+		poutskinintervals++;
+		pinskinintervals++;
+	}
+
+	ptemp = (void *)pinskinintervals;
+
+	for (i=0 ; i<numskins ; i++)
+	{
+		ptemp = Mod_LoadAliasSkin (ptemp,
+				&paliasskingroup->skindescs[i].skin, skinsize, pheader);
+	}
+
+	return ptemp;
+}
+
+
+/*
+=================
+Mod_LoadAliasModel
+=================
+*/
+void Mod_LoadAliasModel (model_t *mod, void *buffer)
+{
+	int					i;
+	mdl_t				*pmodel, *pinmodel;
+	stvert_t			*pstverts, *pinstverts;
+	aliashdr_t			*pheader;
+	mtriangle_t			*ptri;
+	dtriangle_t			*pintriangles;
+	int					version, numframes, numskins;
+	int					size;
+	daliasframetype_t	*pframetype;
+	daliasskintype_t	*pskintype;
+	maliasskindesc_t	*pskindesc;
+	int					skinsize;
+	int					start, end, total;
+	
+	start = Hunk_LowMark ();
+
+	pinmodel = (mdl_t *)buffer;
+
+	version = LittleLong (pinmodel->version);
+	if (version != ALIAS_VERSION)
+		Sys_Error ("%s has wrong version number (%i should be %i)",
+				 mod->name, version, ALIAS_VERSION);
+
+//
+// allocate space for a working header, plus all the data except the frames,
+// skin and group info
+//
+	size = 	sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) *
+			 sizeof (pheader->frames[0]) +
+			sizeof (mdl_t) +
+			LittleLong (pinmodel->numverts) * sizeof (stvert_t) +
+			LittleLong (pinmodel->numtris) * sizeof (mtriangle_t);
+
+	pheader = Hunk_AllocName (size, loadname);
+	pmodel = (mdl_t *) ((byte *)&pheader[1] +
+			(LittleLong (pinmodel->numframes) - 1) *
+			 sizeof (pheader->frames[0]));
+	
+//	mod->cache.data = pheader;
+	mod->flags = LittleLong (pinmodel->flags);
+
+//
+// endian-adjust and copy the data, starting with the alias model header
+//
+	pmodel->boundingradius = LittleFloat (pinmodel->boundingradius);
+	pmodel->numskins = LittleLong (pinmodel->numskins);
+	pmodel->skinwidth = LittleLong (pinmodel->skinwidth);
+	pmodel->skinheight = LittleLong (pinmodel->skinheight);
+
+	if (pmodel->skinheight > MAX_LBM_HEIGHT)
+		Sys_Error ("model %s has a skin taller than %d", mod->name,
+				   MAX_LBM_HEIGHT);
+
+	pmodel->numverts = LittleLong (pinmodel->numverts);
+
+	if (pmodel->numverts <= 0)
+		Sys_Error ("model %s has no vertices", mod->name);
+
+	if (pmodel->numverts > MAXALIASVERTS)
+		Sys_Error ("model %s has too many vertices", mod->name);
+
+	pmodel->numtris = LittleLong (pinmodel->numtris);
+
+	if (pmodel->numtris <= 0)
+		Sys_Error ("model %s has no triangles", mod->name);
+
+	pmodel->numframes = LittleLong (pinmodel->numframes);
+	pmodel->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
+	mod->synctype = LittleLong (pinmodel->synctype);
+	mod->numframes = pmodel->numframes;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		pmodel->scale[i] = LittleFloat (pinmodel->scale[i]);
+		pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
+		pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);
+	}
+
+	numskins = pmodel->numskins;
+	numframes = pmodel->numframes;
+
+	if (pmodel->skinwidth & 0x03)
+		Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4");
+
+	pheader->model = (byte *)pmodel - (byte *)pheader;
+
+//
+// load the skins
+//
+	skinsize = pmodel->skinheight * pmodel->skinwidth;
+
+	if (numskins < 1)
+		Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
+
+	pskintype = (daliasskintype_t *)&pinmodel[1];
+
+	pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
+								loadname);
+
+	pheader->skindesc = (byte *)pskindesc - (byte *)pheader;
+
+	for (i=0 ; i<numskins ; i++)
+	{
+		aliasskintype_t	skintype;
+
+		skintype = LittleLong (pskintype->type);
+		pskindesc[i].type = skintype;
+
+		if (skintype == ALIAS_SKIN_SINGLE)
+		{
+			pskintype = (daliasskintype_t *)
+					Mod_LoadAliasSkin (pskintype + 1,
+									   &pskindesc[i].skin,
+									   skinsize, pheader);
+		}
+		else
+		{
+			pskintype = (daliasskintype_t *)
+					Mod_LoadAliasSkinGroup (pskintype + 1,
+											&pskindesc[i].skin,
+											skinsize, pheader);
+		}
+	}
+
+//
+// set base s and t vertices
+//
+	pstverts = (stvert_t *)&pmodel[1];
+	pinstverts = (stvert_t *)pskintype;
+
+	pheader->stverts = (byte *)pstverts - (byte *)pheader;
+
+	for (i=0 ; i<pmodel->numverts ; i++)
+	{
+		pstverts[i].onseam = LittleLong (pinstverts[i].onseam);
+	// put s and t in 16.16 format
+		pstverts[i].s = LittleLong (pinstverts[i].s) << 16;
+		pstverts[i].t = LittleLong (pinstverts[i].t) << 16;
+	}
+
+//
+// set up the triangles
+//
+	ptri = (mtriangle_t *)&pstverts[pmodel->numverts];
+	pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts];
+
+	pheader->triangles = (byte *)ptri - (byte *)pheader;
+
+	for (i=0 ; i<pmodel->numtris ; i++)
+	{
+		int		j;
+
+		ptri[i].facesfront = LittleLong (pintriangles[i].facesfront);
+
+		for (j=0 ; j<3 ; j++)
+		{
+			ptri[i].vertindex[j] =
+					LittleLong (pintriangles[i].vertindex[j]);
+		}
+	}
+
+//
+// load the frames
+//
+	if (numframes < 1)
+		Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
+
+	pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris];
+
+	for (i=0 ; i<numframes ; i++)
+	{
+		aliasframetype_t	frametype;
+
+		frametype = LittleLong (pframetype->type);
+		pheader->frames[i].type = frametype;
+
+		if (frametype == ALIAS_SINGLE)
+		{
+			pframetype = (daliasframetype_t *)
+					Mod_LoadAliasFrame (pframetype + 1,
+										&pheader->frames[i].frame,
+										pmodel->numverts,
+										&pheader->frames[i].bboxmin,
+										&pheader->frames[i].bboxmax,
+										pheader, pheader->frames[i].name);
+		}
+		else
+		{
+			pframetype = (daliasframetype_t *)
+					Mod_LoadAliasGroup (pframetype + 1,
+										&pheader->frames[i].frame,
+										pmodel->numverts,
+										&pheader->frames[i].bboxmin,
+										&pheader->frames[i].bboxmax,
+										pheader, pheader->frames[i].name);
+		}
+	}
+
+	mod->type = mod_alias;
+
+// FIXME: do this right
+	mod->mins[0] = mod->mins[1] = mod->mins[2] = -16;
+	mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16;
+
+//
+// move the complete, relocatable alias model to the cache
+//	
+	end = Hunk_LowMark ();
+	total = end - start;
+	
+	Cache_Alloc (&mod->cache, total, loadname);
+	if (!mod->cache.data)
+		return;
+	memcpy (mod->cache.data, pheader, total);
+
+	Hunk_FreeToLowMark (start);
+}
+
+//=============================================================================
+
+/*
+=================
+Mod_LoadSpriteFrame
+=================
+*/
+void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe)
+{
+	dspriteframe_t		*pinframe;
+	mspriteframe_t		*pspriteframe;
+	int					i, width, height, size, origin[2];
+	unsigned short		*ppixout;
+	byte				*ppixin;
+
+	pinframe = (dspriteframe_t *)pin;
+
+	width = LittleLong (pinframe->width);
+	height = LittleLong (pinframe->height);
+	size = width * height;
+
+	pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size*r_pixbytes,
+								   loadname);
+
+	Q_memset (pspriteframe, 0, sizeof (mspriteframe_t) + size);
+	*ppframe = pspriteframe;
+
+	pspriteframe->width = width;
+	pspriteframe->height = height;
+	origin[0] = LittleLong (pinframe->origin[0]);
+	origin[1] = LittleLong (pinframe->origin[1]);
+
+	pspriteframe->up = origin[1];
+	pspriteframe->down = origin[1] - height;
+	pspriteframe->left = origin[0];
+	pspriteframe->right = width + origin[0];
+
+	if (r_pixbytes == 1)
+	{
+		Q_memcpy (&pspriteframe->pixels[0], (byte *)(pinframe + 1), size);
+	}
+	else if (r_pixbytes == 2)
+	{
+		ppixin = (byte *)(pinframe + 1);
+		ppixout = (unsigned short *)&pspriteframe->pixels[0];
+
+		for (i=0 ; i<size ; i++)
+			ppixout[i] = d_8to16table[ppixin[i]];
+	}
+	else
+	{
+		Sys_Error ("Mod_LoadSpriteFrame: driver set invalid r_pixbytes: %d\n",
+				 r_pixbytes);
+	}
+
+	return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
+}
+
+
+/*
+=================
+Mod_LoadSpriteGroup
+=================
+*/
+void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe)
+{
+	dspritegroup_t		*pingroup;
+	mspritegroup_t		*pspritegroup;
+	int					i, numframes;
+	dspriteinterval_t	*pin_intervals;
+	float				*poutintervals;
+	void				*ptemp;
+
+	pingroup = (dspritegroup_t *)pin;
+
+	numframes = LittleLong (pingroup->numframes);
+
+	pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +
+				(numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
+
+	pspritegroup->numframes = numframes;
+
+	*ppframe = (mspriteframe_t *)pspritegroup;
+
+	pin_intervals = (dspriteinterval_t *)(pingroup + 1);
+
+	poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
+
+	pspritegroup->intervals = poutintervals;
+
+	for (i=0 ; i<numframes ; i++)
+	{
+		*poutintervals = LittleFloat (pin_intervals->interval);
+		if (*poutintervals <= 0.0)
+			Sys_Error ("Mod_LoadSpriteGroup: interval<=0");
+
+		poutintervals++;
+		pin_intervals++;
+	}
+
+	ptemp = (void *)pin_intervals;
+
+	for (i=0 ; i<numframes ; i++)
+	{
+		ptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i]);
+	}
+
+	return ptemp;
+}
+
+
+/*
+=================
+Mod_LoadSpriteModel
+=================
+*/
+void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+{
+	int					i;
+	int					version;
+	dsprite_t			*pin;
+	msprite_t			*psprite;
+	int					numframes;
+	int					size;
+	dspriteframetype_t	*pframetype;
+	
+	pin = (dsprite_t *)buffer;
+
+	version = LittleLong (pin->version);
+	if (version != SPRITE_VERSION)
+		Sys_Error ("%s has wrong version number "
+				 "(%i should be %i)", mod->name, version, SPRITE_VERSION);
+
+	numframes = LittleLong (pin->numframes);
+
+	size = sizeof (msprite_t) +	(numframes - 1) * sizeof (psprite->frames);
+
+	psprite = Hunk_AllocName (size, loadname);
+
+	mod->cache.data = psprite;
+
+	psprite->type = LittleLong (pin->type);
+	psprite->maxwidth = LittleLong (pin->width);
+	psprite->maxheight = LittleLong (pin->height);
+	psprite->beamlength = LittleFloat (pin->beamlength);
+	mod->synctype = LittleLong (pin->synctype);
+	psprite->numframes = numframes;
+
+	mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;
+	mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2;
+	mod->mins[2] = -psprite->maxheight/2;
+	mod->maxs[2] = psprite->maxheight/2;
+	
+//
+// load the frames
+//
+	if (numframes < 1)
+		Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes);
+
+	mod->numframes = numframes;
+	mod->flags = 0;
+
+	pframetype = (dspriteframetype_t *)(pin + 1);
+
+	for (i=0 ; i<numframes ; i++)
+	{
+		spriteframetype_t	frametype;
+
+		frametype = LittleLong (pframetype->type);
+		psprite->frames[i].type = frametype;
+
+		if (frametype == SPR_SINGLE)
+		{
+			pframetype = (dspriteframetype_t *)
+					Mod_LoadSpriteFrame (pframetype + 1,
+										 &psprite->frames[i].frameptr);
+		}
+		else
+		{
+			pframetype = (dspriteframetype_t *)
+					Mod_LoadSpriteGroup (pframetype + 1,
+										 &psprite->frames[i].frameptr);
+		}
+	}
+
+	mod->type = mod_sprite;
+}
+
+//=============================================================================
+
+/*
+================
+Mod_Print
+================
+*/
+void Mod_Print (void)
+{
+	int		i;
+	model_t	*mod;
+
+	Con_Printf ("Cached models:\n");
+	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
+	{
+		Con_Printf ("%8p : %s",mod->cache.data, mod->name);
+		if (mod->needload & NL_UNREFERENCED)
+			Con_Printf (" (!R)");
+		if (mod->needload & NL_NEEDS_LOADED)
+			Con_Printf (" (!P)");
+		Con_Printf ("\n");
+	}
+}
+
+
diff --git a/quake/src/WinQuake/model.h b/quake/src/WinQuake/model.h
index 312a1f1..f2f0813 100644
--- a/quake/src/WinQuake/model.h
+++ b/quake/src/WinQuake/model.h
@@ -1,382 +1,382 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-#ifndef __MODEL__

-#define __MODEL__

-

-#include "modelgen.h"

-#include "spritegn.h"

-

-/*

-

-d*_t structures are on-disk representations

-m*_t structures are in-memory

-

-*/

-

-/*

-==============================================================================

-

-BRUSH MODELS

-

-==============================================================================

-*/

-

-

-//

-// in memory representation

-//

-// !!! if this is changed, it must be changed in asm_draw.h too !!!

-typedef struct

-{

-	vec3_t		position;

-} mvertex_t;

-

-#define	SIDE_FRONT	0

-#define	SIDE_BACK	1

-#define	SIDE_ON		2

-

-

-// plane_t structure

-// !!! if this is changed, it must be changed in asm_i386.h too !!!

-typedef struct mplane_s

-{

-	vec3_t	normal;

-	float	dist;

-	byte	type;			// for texture axis selection and fast side tests

-	byte	signbits;		// signx + signy<<1 + signz<<1

-	byte	pad[2];

-} mplane_t;

-

-typedef struct texture_s

-{

-	char		name[16];

-	unsigned	width, height;

-	int			anim_total;				// total tenths in sequence ( 0 = no)

-	int			anim_min, anim_max;		// time for this frame min <=time< max

-	struct texture_s *anim_next;		// in the animation sequence

-	struct texture_s *alternate_anims;	// bmodels in frmae 1 use these

-	unsigned	offsets[MIPLEVELS];		// four mip maps stored

-} texture_t;

-

-

-#define	SURF_PLANEBACK		2

-#define	SURF_DRAWSKY		4

-#define SURF_DRAWSPRITE		8

-#define SURF_DRAWTURB		0x10

-#define SURF_DRAWTILED		0x20

-#define SURF_DRAWBACKGROUND	0x40

-

-// !!! if this is changed, it must be changed in asm_draw.h too !!!

-typedef struct

-{

-	unsigned short	v[2];

-	unsigned int	cachededgeoffset;

-} medge_t;

-

-typedef struct

-{

-	float		vecs[2][4];

-	float		mipadjust;

-	texture_t	*texture;

-	int			flags;

-} mtexinfo_t;

-

-typedef struct msurface_s

-{

-	int			visframe;		// should be drawn when node is crossed

-

-	int			dlightframe;

-	int			dlightbits;

-

-	mplane_t	*plane;

-	int			flags;

-

-	int			firstedge;	// look up in model->surfedges[], negative numbers

-	int			numedges;	// are backwards edges

-	

-// surface generation data

-	struct surfcache_s	*cachespots[MIPLEVELS];

-

-	short		texturemins[2];

-	short		extents[2];

-

-	mtexinfo_t	*texinfo;

-	

-// lighting info

-	byte		styles[MAXLIGHTMAPS];

-	byte		*samples;		// [numstyles*surfsize]

-} msurface_t;

-

-typedef struct mnode_s

-{

-// common with leaf

-	int			contents;		// 0, to differentiate from leafs

-	int			visframe;		// node needs to be traversed if current

-	

-	short		minmaxs[6];		// for bounding box culling

-

-	struct mnode_s	*parent;

-

-// node specific

-	mplane_t	*plane;

-	struct mnode_s	*children[2];	

-

-	unsigned short		firstsurface;

-	unsigned short		numsurfaces;

-} mnode_t;

-

-

-

-typedef struct mleaf_s

-{

-// common with node

-	int			contents;		// wil be a negative contents number

-	int			visframe;		// node needs to be traversed if current

-

-	short		minmaxs[6];		// for bounding box culling

-

-	struct mnode_s	*parent;

-

-// leaf specific

-	byte		*compressed_vis;

-	efrag_t		*efrags;

-

-	msurface_t	**firstmarksurface;

-	int			nummarksurfaces;

-	int			key;			// BSP sequence number for leaf's contents

-	byte		ambient_sound_level[NUM_AMBIENTS];

-} mleaf_t;

-

-// !!! if this is changed, it must be changed in asm_i386.h too !!!

-typedef struct

-{

-	dclipnode_t	*clipnodes;

-	mplane_t	*planes;

-	int			firstclipnode;

-	int			lastclipnode;

-	vec3_t		clip_mins;

-	vec3_t		clip_maxs;

-} hull_t;

-

-/*

-==============================================================================

-

-SPRITE MODELS

-

-==============================================================================

-*/

-

-

-// FIXME: shorten these?

-typedef struct mspriteframe_s

-{

-	int		width;

-	int		height;

-	void	*pcachespot;			// remove?

-	float	up, down, left, right;

-	byte	pixels[4];

-} mspriteframe_t;

-

-typedef struct

-{

-	int				numframes;

-	float			*intervals;

-	mspriteframe_t	*frames[1];

-} mspritegroup_t;

-

-typedef struct

-{

-	spriteframetype_t	type;

-	mspriteframe_t		*frameptr;

-} mspriteframedesc_t;

-

-typedef struct

-{

-	int					type;

-	int					maxwidth;

-	int					maxheight;

-	int					numframes;

-	float				beamlength;		// remove?

-	void				*cachespot;		// remove?

-	mspriteframedesc_t	frames[1];

-} msprite_t;

-

-

-/*

-==============================================================================

-

-ALIAS MODELS

-

-Alias models are position independent, so the cache manager can move them.

-==============================================================================

-*/

-

-typedef struct

-{

-	aliasframetype_t	type;

-	trivertx_t			bboxmin;

-	trivertx_t			bboxmax;

-	int					frame;

-	char				name[16];

-} maliasframedesc_t;

-

-typedef struct

-{

-	aliasskintype_t		type;

-	void				*pcachespot;

-	int					skin;

-} maliasskindesc_t;

-

-typedef struct

-{

-	trivertx_t			bboxmin;

-	trivertx_t			bboxmax;

-	int					frame;

-} maliasgroupframedesc_t;

-

-typedef struct

-{

-	int						numframes;

-	int						intervals;

-	maliasgroupframedesc_t	frames[1];

-} maliasgroup_t;

-

-typedef struct

-{

-	int					numskins;

-	int					intervals;

-	maliasskindesc_t	skindescs[1];

-} maliasskingroup_t;

-

-// !!! if this is changed, it must be changed in asm_draw.h too !!!

-typedef struct mtriangle_s {

-	int					facesfront;

-	int					vertindex[3];

-} mtriangle_t;

-

-typedef struct {

-	int					model;

-	int					stverts;

-	int					skindesc;

-	int					triangles;

-	maliasframedesc_t	frames[1];

-} aliashdr_t;

-

-//===================================================================

-

-//

-// Whole model

-//

-

-typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;

-

-#define	EF_ROCKET	1			// leave a trail

-#define	EF_GRENADE	2			// leave a trail

-#define	EF_GIB		4			// leave a trail

-#define	EF_ROTATE	8			// rotate (bonus items)

-#define	EF_TRACER	16			// green split trail

-#define	EF_ZOMGIB	32			// small blood trail

-#define	EF_TRACER2	64			// orange split trail + rotate

-#define	EF_TRACER3	128			// purple trail

-

-typedef struct model_s

-{

-	char		name[MAX_QPATH];

-	qboolean	needload;		// bmodels and sprites don't cache normally

-

-	modtype_t	type;

-	int			numframes;

-	synctype_t	synctype;

-	

-	int			flags;

-

-//

-// volume occupied by the model

-//		

-	vec3_t		mins, maxs;

-	float		radius;

-

-//

-// brush model

-//

-	int			firstmodelsurface, nummodelsurfaces;

-

-	int			numsubmodels;

-	dmodel_t	*submodels;

-

-	int			numplanes;

-	mplane_t	*planes;

-

-	int			numleafs;		// number of visible leafs, not counting 0

-	mleaf_t		*leafs;

-

-	int			numvertexes;

-	mvertex_t	*vertexes;

-

-	int			numedges;

-	medge_t		*edges;

-

-	int			numnodes;

-	mnode_t		*nodes;

-

-	int			numtexinfo;

-	mtexinfo_t	*texinfo;

-

-	int			numsurfaces;

-	msurface_t	*surfaces;

-

-	int			numsurfedges;

-	int			*surfedges;

-

-	int			numclipnodes;

-	dclipnode_t	*clipnodes;

-

-	int			nummarksurfaces;

-	msurface_t	**marksurfaces;

-

-	hull_t		hulls[MAX_MAP_HULLS];

-

-	int			numtextures;

-	texture_t	**textures;

-

-	byte		*visdata;

-	byte		*lightdata;

-	char		*entities;

-

-//

-// additional model data

-//

-	cache_user_t	cache;		// only access through Mod_Extradata

-

-} model_t;

-

-//============================================================================

-

-void	Mod_Init (void);

-void	Mod_ClearAll (void);

-model_t *Mod_ForName (char *name, qboolean crash);

-void	*Mod_Extradata (model_t *mod);	// handles caching

-void	Mod_TouchModel (char *name);

-

-mleaf_t *Mod_PointInLeaf (float *p, model_t *model);

-byte	*Mod_LeafPVS (mleaf_t *leaf, model_t *model);

-

-#endif	// __MODEL__

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifndef __MODEL__
+#define __MODEL__
+
+#include "modelgen.h"
+#include "spritegn.h"
+
+/*
+
+d*_t structures are on-disk representations
+m*_t structures are in-memory
+
+*/
+
+/*
+==============================================================================
+
+BRUSH MODELS
+
+==============================================================================
+*/
+
+
+//
+// in memory representation
+//
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct
+{
+	vec3_t		position;
+} mvertex_t;
+
+#define	SIDE_FRONT	0
+#define	SIDE_BACK	1
+#define	SIDE_ON		2
+
+
+// plane_t structure
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct mplane_s
+{
+	vec3_t	normal;
+	float	dist;
+	byte	type;			// for texture axis selection and fast side tests
+	byte	signbits;		// signx + signy<<1 + signz<<1
+	byte	pad[2];
+} mplane_t;
+
+typedef struct texture_s
+{
+	char		name[16];
+	unsigned	width, height;
+	int			anim_total;				// total tenths in sequence ( 0 = no)
+	int			anim_min, anim_max;		// time for this frame min <=time< max
+	struct texture_s *anim_next;		// in the animation sequence
+	struct texture_s *alternate_anims;	// bmodels in frmae 1 use these
+	unsigned	offsets[MIPLEVELS];		// four mip maps stored
+} texture_t;
+
+
+#define	SURF_PLANEBACK		2
+#define	SURF_DRAWSKY		4
+#define SURF_DRAWSPRITE		8
+#define SURF_DRAWTURB		0x10
+#define SURF_DRAWTILED		0x20
+#define SURF_DRAWBACKGROUND	0x40
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct
+{
+	unsigned short	v[2];
+	unsigned int	cachededgeoffset;
+} medge_t;
+
+typedef struct
+{
+	float		vecs[2][4];
+	float		mipadjust;
+	texture_t	*texture;
+	int			flags;
+} mtexinfo_t;
+
+typedef struct msurface_s
+{
+	int			visframe;		// should be drawn when node is crossed
+
+	int			dlightframe;
+	int			dlightbits;
+
+	mplane_t	*plane;
+	int			flags;
+
+	int			firstedge;	// look up in model->surfedges[], negative numbers
+	int			numedges;	// are backwards edges
+	
+// surface generation data
+	struct surfcache_s	*cachespots[MIPLEVELS];
+
+	short		texturemins[2];
+	short		extents[2];
+
+	mtexinfo_t	*texinfo;
+	
+// lighting info
+	byte		styles[MAXLIGHTMAPS];
+	byte		*samples;		// [numstyles*surfsize]
+} msurface_t;
+
+typedef struct mnode_s
+{
+// common with leaf
+	int			contents;		// 0, to differentiate from leafs
+	int			visframe;		// node needs to be traversed if current
+	
+	short		minmaxs[6];		// for bounding box culling
+
+	struct mnode_s	*parent;
+
+// node specific
+	mplane_t	*plane;
+	struct mnode_s	*children[2];	
+
+	unsigned short		firstsurface;
+	unsigned short		numsurfaces;
+} mnode_t;
+
+
+
+typedef struct mleaf_s
+{
+// common with node
+	int			contents;		// wil be a negative contents number
+	int			visframe;		// node needs to be traversed if current
+
+	short		minmaxs[6];		// for bounding box culling
+
+	struct mnode_s	*parent;
+
+// leaf specific
+	byte		*compressed_vis;
+	efrag_t		*efrags;
+
+	msurface_t	**firstmarksurface;
+	int			nummarksurfaces;
+	int			key;			// BSP sequence number for leaf's contents
+	byte		ambient_sound_level[NUM_AMBIENTS];
+} mleaf_t;
+
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct
+{
+	dclipnode_t	*clipnodes;
+	mplane_t	*planes;
+	int			firstclipnode;
+	int			lastclipnode;
+	vec3_t		clip_mins;
+	vec3_t		clip_maxs;
+} hull_t;
+
+/*
+==============================================================================
+
+SPRITE MODELS
+
+==============================================================================
+*/
+
+
+// FIXME: shorten these?
+typedef struct mspriteframe_s
+{
+	int		width;
+	int		height;
+	void	*pcachespot;			// remove?
+	float	up, down, left, right;
+	byte	pixels[4];
+} mspriteframe_t;
+
+typedef struct
+{
+	int				numframes;
+	float			*intervals;
+	mspriteframe_t	*frames[1];
+} mspritegroup_t;
+
+typedef struct
+{
+	spriteframetype_t	type;
+	mspriteframe_t		*frameptr;
+} mspriteframedesc_t;
+
+typedef struct
+{
+	int					type;
+	int					maxwidth;
+	int					maxheight;
+	int					numframes;
+	float				beamlength;		// remove?
+	void				*cachespot;		// remove?
+	mspriteframedesc_t	frames[1];
+} msprite_t;
+
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+Alias models are position independent, so the cache manager can move them.
+==============================================================================
+*/
+
+typedef struct
+{
+	aliasframetype_t	type;
+	trivertx_t			bboxmin;
+	trivertx_t			bboxmax;
+	int					frame;
+	char				name[16];
+} maliasframedesc_t;
+
+typedef struct
+{
+	aliasskintype_t		type;
+	void				*pcachespot;
+	int					skin;
+} maliasskindesc_t;
+
+typedef struct
+{
+	trivertx_t			bboxmin;
+	trivertx_t			bboxmax;
+	int					frame;
+} maliasgroupframedesc_t;
+
+typedef struct
+{
+	int						numframes;
+	int						intervals;
+	maliasgroupframedesc_t	frames[1];
+} maliasgroup_t;
+
+typedef struct
+{
+	int					numskins;
+	int					intervals;
+	maliasskindesc_t	skindescs[1];
+} maliasskingroup_t;
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct mtriangle_s {
+	int					facesfront;
+	int					vertindex[3];
+} mtriangle_t;
+
+typedef struct {
+	int					model;
+	int					stverts;
+	int					skindesc;
+	int					triangles;
+	maliasframedesc_t	frames[1];
+} aliashdr_t;
+
+//===================================================================
+
+//
+// Whole model
+//
+
+typedef enum {mod_brush, mod_sprite, mod_alias, modtype_t_max = 1 << 30} modtype_t;
+
+#define	EF_ROCKET	1			// leave a trail
+#define	EF_GRENADE	2			// leave a trail
+#define	EF_GIB		4			// leave a trail
+#define	EF_ROTATE	8			// rotate (bonus items)
+#define	EF_TRACER	16			// green split trail
+#define	EF_ZOMGIB	32			// small blood trail
+#define	EF_TRACER2	64			// orange split trail + rotate
+#define	EF_TRACER3	128			// purple trail
+
+typedef struct model_s
+{
+	char		name[MAX_QPATH];
+	qboolean	needload;		// bmodels and sprites don't cache normally
+
+	modtype_t	type;
+	int			numframes;
+	synctype_t	synctype;
+	
+	int			flags;
+
+//
+// volume occupied by the model
+//		
+	vec3_t		mins, maxs;
+	float		radius;
+
+//
+// brush model
+//
+	int			firstmodelsurface, nummodelsurfaces;
+
+	int			numsubmodels;
+	dmodel_t	*submodels;
+
+	int			numplanes;
+	mplane_t	*planes;
+
+	int			numleafs;		// number of visible leafs, not counting 0
+	mleaf_t		*leafs;
+
+	int			numvertexes;
+	mvertex_t	*vertexes;
+
+	int			numedges;
+	medge_t		*edges;
+
+	int			numnodes;
+	mnode_t		*nodes;
+
+	int			numtexinfo;
+	mtexinfo_t	*texinfo;
+
+	int			numsurfaces;
+	msurface_t	*surfaces;
+
+	int			numsurfedges;
+	int			*surfedges;
+
+	int			numclipnodes;
+	dclipnode_t	*clipnodes;
+
+	int			nummarksurfaces;
+	msurface_t	**marksurfaces;
+
+	hull_t		hulls[MAX_MAP_HULLS];
+
+	int			numtextures;
+	texture_t	**textures;
+
+	byte		*visdata;
+	byte		*lightdata;
+	char		*entities;
+
+//
+// additional model data
+//
+	cache_user_t	cache;		// only access through Mod_Extradata
+
+} model_t;
+
+//============================================================================
+
+void	Mod_Init (void);
+void	Mod_ClearAll (void);
+model_t *Mod_ForName (const char *name, qboolean crash);
+void	*Mod_Extradata (model_t *mod);	// handles caching
+void	Mod_TouchModel (const char *name);
+
+mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
+byte	*Mod_LeafPVS (mleaf_t *leaf, model_t *model);
+
+#endif	// __MODEL__
diff --git a/quake/src/WinQuake/modelgen.h b/quake/src/WinQuake/modelgen.h
index 76cb956..c9f5281 100644
--- a/quake/src/WinQuake/modelgen.h
+++ b/quake/src/WinQuake/modelgen.h
@@ -49,12 +49,12 @@
 // must match definition in spritegn.h

 #ifndef SYNCTYPE_T

 #define SYNCTYPE_T

-typedef enum {ST_SYNC=0, ST_RAND } synctype_t;

+typedef enum {ST_SYNC=0, ST_RAND, synctype_t_max = 1 << 30 } synctype_t;

 #endif

 

-typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t;

+typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP, aliasframetype_t_max = 1 << 30 } aliasframetype_t;

 

-typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t;

+typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP, aliasskintype_t_max= 1 << 30 } aliasskintype_t;

 

 typedef struct {

 	int			ident;

diff --git a/quake/src/WinQuake/mplib.c b/quake/src/WinQuake/mplib.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/mplib.c
rename to quake/src/WinQuake/mplib.cpp
diff --git a/quake/src/WinQuake/mplpc.c b/quake/src/WinQuake/mplpc.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/mplpc.c
rename to quake/src/WinQuake/mplpc.cpp
diff --git a/quake/src/WinQuake/net.h b/quake/src/WinQuake/net.h
index c84cef4..2c19447 100644
--- a/quake/src/WinQuake/net.h
+++ b/quake/src/WinQuake/net.h
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // net.h -- quake's interface to the networking layer
 
 struct qsockaddr
@@ -154,7 +154,7 @@
 
 typedef struct
 {
-	char		*name;
+	const char		*name;
 	qboolean	initialized;
 	int			controlSock;
 	int			(*Init) (void);
@@ -168,10 +168,10 @@
 	int 		(*Write) (int socket, byte *buf, int len, struct qsockaddr *addr);
 	int 		(*Broadcast) (int socket, byte *buf, int len);
 	char *		(*AddrToString) (struct qsockaddr *addr);
-	int 		(*StringToAddr) (char *string, struct qsockaddr *addr);
+	int 		(*StringToAddr) (const char *string, struct qsockaddr *addr);
 	int 		(*GetSocketAddr) (int socket, struct qsockaddr *addr);
 	int 		(*GetNameFromAddr) (struct qsockaddr *addr, char *name);
-	int 		(*GetAddrFromName) (char *name, struct qsockaddr *addr);
+	int 		(*GetAddrFromName) (const char *name, struct qsockaddr *addr);
 	int			(*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2);
 	int			(*GetSocketPort) (struct qsockaddr *addr);
 	int			(*SetSocketPort) (struct qsockaddr *addr, int port);
@@ -183,12 +183,12 @@
 
 typedef struct
 {
-	char		*name;
+	const char		*name;
 	qboolean	initialized;
 	int			(*Init) (void);
 	void		(*Listen) (qboolean state);
 	void		(*SearchForHosts) (qboolean xmit);
-	qsocket_t	*(*Connect) (char *host);
+	qsocket_t	*(*Connect) (const char *host);
 	qsocket_t 	*(*CheckNewConnections) (void);
 	int			(*QGetMessage) (qsocket_t *sock);
 	int			(*QSendMessage) (qsocket_t *sock, sizebuf_t *data);
@@ -273,7 +273,7 @@
 struct qsocket_s	*NET_CheckNewConnections (void);
 // returns a new connection number if there is one pending, else -1
 
-struct qsocket_s	*NET_Connect (char *host);
+struct qsocket_s	*NET_Connect (const char *host);
 // called by client to connect to a host.  Returns -1 if not able to
 
 qboolean NET_CanSendMessage (qsocket_t *sock);
@@ -314,7 +314,7 @@
 {
 	struct _PollProcedure	*next;
 	double					nextTime;
-	void					(*procedure)();
+	void					(*procedure)(void*);
 	void					*arg;
 } PollProcedure;
 
diff --git a/quake/src/WinQuake/net_bsd.c b/quake/src/WinQuake/net_bsd.cpp
old mode 100644
new mode 100755
similarity index 97%
rename from quake/src/WinQuake/net_bsd.c
rename to quake/src/WinQuake/net_bsd.cpp
index 2da06de..3de7737
--- a/quake/src/WinQuake/net_bsd.c
+++ b/quake/src/WinQuake/net_bsd.cpp
@@ -38,7 +38,8 @@
 	Loop_CanSendMessage,

 	Loop_CanSendUnreliableMessage,

 	Loop_Close,

-	Loop_Shutdown

+	Loop_Shutdown,

+	0

 	}

 	,

 	{

@@ -55,7 +56,8 @@
 	Datagram_CanSendMessage,

 	Datagram_CanSendUnreliableMessage,

 	Datagram_Close,

-	Datagram_Shutdown

+	Datagram_Shutdown,

+	0

 	}

 };

 

diff --git a/quake/src/WinQuake/net_bw.c b/quake/src/WinQuake/net_bw.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_bw.c
rename to quake/src/WinQuake/net_bw.cpp
diff --git a/quake/src/WinQuake/net_comx.c b/quake/src/WinQuake/net_comx.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_comx.c
rename to quake/src/WinQuake/net_comx.cpp
diff --git a/quake/src/WinQuake/net_dgrm.c b/quake/src/WinQuake/net_dgrm.cpp
old mode 100644
new mode 100755
similarity index 94%
rename from quake/src/WinQuake/net_dgrm.c
rename to quake/src/WinQuake/net_dgrm.cpp
index a08b3d3..6b9b38a
--- a/quake/src/WinQuake/net_dgrm.c
+++ b/quake/src/WinQuake/net_dgrm.cpp
@@ -1,1390 +1,1393 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_dgrm.c

-

-// This is enables a simple IP banning mechanism

-#define BAN_TEST

-

-#ifdef BAN_TEST

-#if defined(_WIN32)

-#include <windows.h>

-#elif defined (NeXT)

-#include <sys/socket.h>

-#include <arpa/inet.h>

-#else

-#define AF_INET 		2	/* internet */

-struct in_addr

-{

-	union

-	{

-		struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;

-		struct { unsigned short s_w1,s_w2; } S_un_w;

-		unsigned long S_addr;

-	} S_un;

-};

-#define	s_addr	S_un.S_addr	/* can be used for most tcp & ip code */

-struct sockaddr_in

-{

-    short			sin_family;

-    unsigned short	sin_port;

-	struct in_addr	sin_addr;

-    char			sin_zero[8];

-};

-char *inet_ntoa(struct in_addr in);

-unsigned long inet_addr(const char *cp);

-#endif

-#endif	// BAN_TEST

-

-#include "quakedef.h"

-#include "net_dgrm.h"

-

-// these two macros are to make the code more readable

-#define sfunc	net_landrivers[sock->landriver]

-#define dfunc	net_landrivers[net_landriverlevel]

-

-static int net_landriverlevel;

-

-/* statistic counters */

-int	packetsSent = 0;

-int	packetsReSent = 0;

-int packetsReceived = 0;

-int receivedDuplicateCount = 0;

-int shortPacketCount = 0;

-int droppedDatagrams;

-

-static int myDriverLevel;

-

-struct

-{

-	unsigned int	length;

-	unsigned int	sequence;

-	byte			data[MAX_DATAGRAM];

-} packetBuffer;

-

-extern int m_return_state;

-extern int m_state;

-extern qboolean m_return_onerror;

-extern char m_return_reason[32];

-

-

-#ifdef DEBUG

-char *StrAddr (struct qsockaddr *addr)

-{

-	static char buf[34];

-	byte *p = (byte *)addr;

-	int n;

-

-	for (n = 0; n < 16; n++)

-		sprintf (buf + n * 2, "%02x", *p++);

-	return buf;

-}

-#endif

-

-

-#ifdef BAN_TEST

-unsigned long banAddr = 0x00000000;

-unsigned long banMask = 0xffffffff;

-

-void NET_Ban_f (void)

-{

-	char	addrStr [32];

-	char	maskStr [32];

-	void	(*print) (char *fmt, ...);

-

-	if (cmd_source == src_command)

-	{

-		if (!sv.active)

-		{

-			Cmd_ForwardToServer ();

-			return;

-		}

-		print = Con_Printf;

-	}

-	else

-	{

-		if (pr_global_struct->deathmatch && !host_client->privileged)

-			return;

-		print = SV_ClientPrintf;

-	}

-

-	switch (Cmd_Argc ())

-	{

-		case 1:

-			if (((struct in_addr *)&banAddr)->s_addr)

-			{

-				Q_strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));

-				Q_strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));

-				print("Banning %s [%s]\n", addrStr, maskStr);

-			}

-			else

-				print("Banning not active\n");

-			break;

-

-		case 2:

-			if (Q_strcasecmp(Cmd_Argv(1), "off") == 0)

-				banAddr = 0x00000000;

-			else

-				banAddr = inet_addr(Cmd_Argv(1));

-			banMask = 0xffffffff;

-			break;

-

-		case 3:

-			banAddr = inet_addr(Cmd_Argv(1));

-			banMask = inet_addr(Cmd_Argv(2));

-			break;

-

-		default:

-			print("BAN ip_address [mask]\n");

-			break;

-	}

-}

-#endif

-

-

-int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)

-{

-	unsigned int	packetLen;

-	unsigned int	dataLen;

-	unsigned int	eom;

-

-#ifdef DEBUG

-	if (data->cursize == 0)

-		Sys_Error("Datagram_SendMessage: zero length message\n");

-

-	if (data->cursize > NET_MAXMESSAGE)

-		Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);

-

-	if (sock->canSend == false)

-		Sys_Error("SendMessage: called with canSend == false\n");

-#endif

-

-	Q_memcpy(sock->sendMessage, data->data, data->cursize);

-	sock->sendMessageLength = data->cursize;

-

-	if (data->cursize <= MAX_DATAGRAM)

-	{

-		dataLen = data->cursize;

-		eom = NETFLAG_EOM;

-	}

-	else

-	{

-		dataLen = MAX_DATAGRAM;

-		eom = 0;

-	}

-	packetLen = NET_HEADERSIZE + dataLen;

-

-	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));

-	packetBuffer.sequence = BigLong(sock->sendSequence++);

-	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);

-

-	sock->canSend = false;

-

-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)

-		return -1;

-

-	sock->lastSendTime = net_time;

-	packetsSent++;

-	return 1;

-}

-

-

-int SendMessageNext (qsocket_t *sock)

-{

-	unsigned int	packetLen;

-	unsigned int	dataLen;

-	unsigned int	eom;

-

-	if (sock->sendMessageLength <= MAX_DATAGRAM)

-	{

-		dataLen = sock->sendMessageLength;

-		eom = NETFLAG_EOM;

-	}

-	else

-	{

-		dataLen = MAX_DATAGRAM;

-		eom = 0;

-	}

-	packetLen = NET_HEADERSIZE + dataLen;

-

-	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));

-	packetBuffer.sequence = BigLong(sock->sendSequence++);

-	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);

-

-	sock->sendNext = false;

-

-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)

-		return -1;

-

-	sock->lastSendTime = net_time;

-	packetsSent++;

-	return 1;

-}

-

-

-int ReSendMessage (qsocket_t *sock)

-{

-	unsigned int	packetLen;

-	unsigned int	dataLen;

-	unsigned int	eom;

-

-	if (sock->sendMessageLength <= MAX_DATAGRAM)

-	{

-		dataLen = sock->sendMessageLength;

-		eom = NETFLAG_EOM;

-	}

-	else

-	{

-		dataLen = MAX_DATAGRAM;

-		eom = 0;

-	}

-	packetLen = NET_HEADERSIZE + dataLen;

-

-	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));

-	packetBuffer.sequence = BigLong(sock->sendSequence - 1);

-	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);

-

-	sock->sendNext = false;

-

-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)

-		return -1;

-

-	sock->lastSendTime = net_time;

-	packetsReSent++;

-	return 1;

-}

-

-

-qboolean Datagram_CanSendMessage (qsocket_t *sock)

-{

-	if (sock->sendNext)

-		SendMessageNext (sock);

-

-	return sock->canSend;

-}

-

-

-qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock)

-{

-	return true;

-}

-

-

-int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)

-{

-	int 	packetLen;

-

-#ifdef DEBUG

-	if (data->cursize == 0)

-		Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");

-

-	if (data->cursize > MAX_DATAGRAM)

-		Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);

-#endif

-

-	packetLen = NET_HEADERSIZE + data->cursize;

-

-	packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);

-	packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);

-	Q_memcpy (packetBuffer.data, data->data, data->cursize);

-

-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)

-		return -1;

-

-	packetsSent++;

-	return 1;

-}

-

-

-int	Datagram_GetMessage (qsocket_t *sock)

-{

-	unsigned int	length;

-	unsigned int	flags;

-	int				ret = 0;

-	struct qsockaddr readaddr;

-	unsigned int	sequence;

-	unsigned int	count;

-

-	if (!sock->canSend)

-		if ((net_time - sock->lastSendTime) > 1.0)

-			ReSendMessage (sock);

-

-	while(1)

-	{	

-		length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);

-

-//	if ((rand() & 255) > 220)

-//		continue;

-

-		if (length == 0)

-			break;

-

-		if (length == -1)

-		{

-			Con_Printf("Read error\n");

-			return -1;

-		}

-

-		if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)

-		{

-#ifdef DEBUG

-			Con_DPrintf("Forged packet received\n");

-			Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));

-			Con_DPrintf("Received: %s\n", StrAddr (&readaddr));

-#endif

-			continue;

-		}

-

-		if (length < NET_HEADERSIZE)

-		{

-			shortPacketCount++;

-			continue;

-		}

-

-		length = BigLong(packetBuffer.length);

-		flags = length & (~NETFLAG_LENGTH_MASK);

-		length &= NETFLAG_LENGTH_MASK;

-

-		if (flags & NETFLAG_CTL)

-			continue;

-

-		sequence = BigLong(packetBuffer.sequence);

-		packetsReceived++;

-

-		if (flags & NETFLAG_UNRELIABLE)

-		{

-			if (sequence < sock->unreliableReceiveSequence)

-			{

-				Con_DPrintf("Got a stale datagram\n");

-				ret = 0;

-				break;

-			}

-			if (sequence != sock->unreliableReceiveSequence)

-			{

-				count = sequence - sock->unreliableReceiveSequence;

-				droppedDatagrams += count;

-				Con_DPrintf("Dropped %u datagram(s)\n", count);

-			}

-			sock->unreliableReceiveSequence = sequence + 1;

-

-			length -= NET_HEADERSIZE;

-

-			SZ_Clear (&net_message);

-			SZ_Write (&net_message, packetBuffer.data, length);

-

-			ret = 2;

-			break;

-		}

-

-		if (flags & NETFLAG_ACK)

-		{

-			if (sequence != (sock->sendSequence - 1))

-			{

-				Con_DPrintf("Stale ACK received\n");

-				continue;

-			}

-			if (sequence == sock->ackSequence)

-			{

-				sock->ackSequence++;

-				if (sock->ackSequence != sock->sendSequence)

-					Con_DPrintf("ack sequencing error\n");

-			}

-			else

-			{

-				Con_DPrintf("Duplicate ACK received\n");

-				continue;

-			}

-			sock->sendMessageLength -= MAX_DATAGRAM;

-			if (sock->sendMessageLength > 0)

-			{

-				Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);

-				sock->sendNext = true;

-			}

-			else

-			{

-				sock->sendMessageLength = 0;

-				sock->canSend = true;

-			}

-			continue;

-		}

-

-		if (flags & NETFLAG_DATA)

-		{

-			packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);

-			packetBuffer.sequence = BigLong(sequence);

-			sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);

-

-			if (sequence != sock->receiveSequence)

-			{

-				receivedDuplicateCount++;

-				continue;

-			}

-			sock->receiveSequence++;

-

-			length -= NET_HEADERSIZE;

-

-			if (flags & NETFLAG_EOM)

-			{

-				SZ_Clear(&net_message);

-				SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);

-				SZ_Write(&net_message, packetBuffer.data, length);

-				sock->receiveMessageLength = 0;

-

-				ret = 1;

-				break;

-			}

-

-			Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);

-			sock->receiveMessageLength += length;

-			continue;

-		}

-	}

-

-	if (sock->sendNext)

-		SendMessageNext (sock);

-

-	return ret;

-}

-

-

-void PrintStats(qsocket_t *s)

-{

-	Con_Printf("canSend = %4u   \n", s->canSend);

-	Con_Printf("sendSeq = %4u   ", s->sendSequence);

-	Con_Printf("recvSeq = %4u   \n", s->receiveSequence);

-	Con_Printf("\n");

-}

-

-void NET_Stats_f (void)

-{

-	qsocket_t	*s;

-

-	if (Cmd_Argc () == 1)

-	{

-		Con_Printf("unreliable messages sent   = %i\n", unreliableMessagesSent);

-		Con_Printf("unreliable messages recv   = %i\n", unreliableMessagesReceived);

-		Con_Printf("reliable messages sent     = %i\n", messagesSent);

-		Con_Printf("reliable messages received = %i\n", messagesReceived);

-		Con_Printf("packetsSent                = %i\n", packetsSent);

-		Con_Printf("packetsReSent              = %i\n", packetsReSent);

-		Con_Printf("packetsReceived            = %i\n", packetsReceived);

-		Con_Printf("receivedDuplicateCount     = %i\n", receivedDuplicateCount);

-		Con_Printf("shortPacketCount           = %i\n", shortPacketCount);

-		Con_Printf("droppedDatagrams           = %i\n", droppedDatagrams);

-	}

-	else if (Q_strcmp(Cmd_Argv(1), "*") == 0)

-	{

-		for (s = net_activeSockets; s; s = s->next)

-			PrintStats(s);

-		for (s = net_freeSockets; s; s = s->next)

-			PrintStats(s);

-	}

-	else

-	{

-		for (s = net_activeSockets; s; s = s->next)

-			if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)

-				break;

-		if (s == NULL)

-			for (s = net_freeSockets; s; s = s->next)

-				if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)

-					break;

-		if (s == NULL)

-			return;

-		PrintStats(s);

-	}

-}

-

-

-static qboolean testInProgress = false;

-static int		testPollCount;

-static int		testDriver;

-static int		testSocket;

-

-static void Test_Poll(void);

-PollProcedure	testPollProcedure = {NULL, 0.0, Test_Poll};

-

-static void Test_Poll(void)

-{

-	struct qsockaddr clientaddr;

-	int		control;

-	int		len;

-	char	name[32];

-	char	address[64];

-	int		colors;

-	int		frags;

-	int		connectTime;

-	byte	playerNumber;

-

-	net_landriverlevel = testDriver;

-

-	while (1)

-	{

-		len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);

-		if (len < sizeof(int))

-			break;

-

-		net_message.cursize = len;

-

-		MSG_BeginReading ();

-		control = BigLong(*((int *)net_message.data));

-		MSG_ReadLong();

-		if (control == -1)

-			break;

-		if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)

-			break;

-		if ((control & NETFLAG_LENGTH_MASK) != len)

-			break;

-

-		if (MSG_ReadByte() != CCREP_PLAYER_INFO)

-			Sys_Error("Unexpected repsonse to Player Info request\n");

-

-		playerNumber = MSG_ReadByte();

-		Q_strcpy(name, MSG_ReadString());

-		colors = MSG_ReadLong();

-		frags = MSG_ReadLong();

-		connectTime = MSG_ReadLong();

-		Q_strcpy(address, MSG_ReadString());

-

-		Con_Printf("%s\n  frags:%3i  colors:%u %u  time:%u\n  %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);

-	}

-

-	testPollCount--;

-	if (testPollCount)

-	{

-		SchedulePollProcedure(&testPollProcedure, 0.1);

-	}

-	else

-	{

-		dfunc.CloseSocket(testSocket);

-		testInProgress = false;

-	}

-}

-

-static void Test_f (void)

-{

-	char	*host;

-	int		n;

-	int		max = MAX_SCOREBOARD;

-	struct qsockaddr sendaddr;

-

-	if (testInProgress)

-		return;

-

-	host = Cmd_Argv (1);

-

-	if (host && hostCacheCount)

-	{

-		for (n = 0; n < hostCacheCount; n++)

-			if (Q_strcasecmp (host, hostcache[n].name) == 0)

-			{

-				if (hostcache[n].driver != myDriverLevel)

-					continue;

-				net_landriverlevel = hostcache[n].ldriver;

-				max = hostcache[n].maxusers;

-				Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));

-				break;

-			}

-		if (n < hostCacheCount)

-			goto JustDoIt;

-	}

-

-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)

-	{

-		if (!net_landrivers[net_landriverlevel].initialized)

-			continue;

-

-		// see if we can resolve the host name

-		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)

-			break;

-	}

-	if (net_landriverlevel == net_numlandrivers)

-		return;

-

-JustDoIt:

-	testSocket = dfunc.OpenSocket(0);

-	if (testSocket == -1)

-		return;

-

-	testInProgress = true;

-	testPollCount = 20;

-	testDriver = net_landriverlevel;

-

-	for (n = 0; n < max; n++)

-	{

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);

-		MSG_WriteByte(&net_message, n);

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | 	(net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);

-	}

-	SZ_Clear(&net_message);

-	SchedulePollProcedure(&testPollProcedure, 0.1);

-}

-

-

-static qboolean test2InProgress = false;

-static int		test2Driver;

-static int		test2Socket;

-

-static void Test2_Poll(void);

-PollProcedure	test2PollProcedure = {NULL, 0.0, Test2_Poll};

-

-static void Test2_Poll(void)

-{

-	struct qsockaddr clientaddr;

-	int		control;

-	int		len;

-	char	name[256];

-	char	value[256];

-

-	net_landriverlevel = test2Driver;

-	name[0] = 0;

-

-	len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);

-	if (len < sizeof(int))

-		goto Reschedule;

-

-	net_message.cursize = len;

-

-	MSG_BeginReading ();

-	control = BigLong(*((int *)net_message.data));

-	MSG_ReadLong();

-	if (control == -1)

-		goto Error;

-	if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)

-		goto Error;

-	if ((control & NETFLAG_LENGTH_MASK) != len)

-		goto Error;

-

-	if (MSG_ReadByte() != CCREP_RULE_INFO)

-		goto Error;

-

-	Q_strcpy(name, MSG_ReadString());

-	if (name[0] == 0)

-		goto Done;

-	Q_strcpy(value, MSG_ReadString());

-

-	Con_Printf("%-16.16s  %-16.16s\n", name, value);

-

-	SZ_Clear(&net_message);

-	// save space for the header, filled in later

-	MSG_WriteLong(&net_message, 0);

-	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);

-	MSG_WriteString(&net_message, name);

-	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);

-	SZ_Clear(&net_message);

-

-Reschedule:

-	SchedulePollProcedure(&test2PollProcedure, 0.05);

-	return;

-

-Error:

-	Con_Printf("Unexpected repsonse to Rule Info request\n");

-Done:

-	dfunc.CloseSocket(test2Socket);

-	test2InProgress = false;

-	return;

-}

-

-static void Test2_f (void)

-{

-	char	*host;

-	int		n;

-	struct qsockaddr sendaddr;

-

-	if (test2InProgress)

-		return;

-

-	host = Cmd_Argv (1);

-

-	if (host && hostCacheCount)

-	{

-		for (n = 0; n < hostCacheCount; n++)

-			if (Q_strcasecmp (host, hostcache[n].name) == 0)

-			{

-				if (hostcache[n].driver != myDriverLevel)

-					continue;

-				net_landriverlevel = hostcache[n].ldriver;

-				Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));

-				break;

-			}

-		if (n < hostCacheCount)

-			goto JustDoIt;

-	}

-

-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)

-	{

-		if (!net_landrivers[net_landriverlevel].initialized)

-			continue;

-

-		// see if we can resolve the host name

-		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)

-			break;

-	}

-	if (net_landriverlevel == net_numlandrivers)

-		return;

-

-JustDoIt:

-	test2Socket = dfunc.OpenSocket(0);

-	if (test2Socket == -1)

-		return;

-

-	test2InProgress = true;

-	test2Driver = net_landriverlevel;

-

-	SZ_Clear(&net_message);

-	// save space for the header, filled in later

-	MSG_WriteLong(&net_message, 0);

-	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);

-	MSG_WriteString(&net_message, "");

-	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);

-	SZ_Clear(&net_message);

-	SchedulePollProcedure(&test2PollProcedure, 0.05);

-}

-

-

-int Datagram_Init (void)

-{

-	int i;

-	int csock;

-

-	myDriverLevel = net_driverlevel;

-	Cmd_AddCommand ("net_stats", NET_Stats_f);

-

-	if (COM_CheckParm("-nolan"))

-		return -1;

-

-	for (i = 0; i < net_numlandrivers; i++)

-		{

-		csock = net_landrivers[i].Init ();

-		if (csock == -1)

-			continue;

-		net_landrivers[i].initialized = true;

-		net_landrivers[i].controlSock = csock;

-		}

-

-#ifdef BAN_TEST

-	Cmd_AddCommand ("ban", NET_Ban_f);

-#endif

-	Cmd_AddCommand ("test", Test_f);

-	Cmd_AddCommand ("test2", Test2_f);

-

-	return 0;

-}

-

-

-void Datagram_Shutdown (void)

-{

-	int i;

-

-//

-// shutdown the lan drivers

-//

-	for (i = 0; i < net_numlandrivers; i++)

-	{

-		if (net_landrivers[i].initialized)

-		{

-			net_landrivers[i].Shutdown ();

-			net_landrivers[i].initialized = false;

-		}

-	}

-}

-

-

-void Datagram_Close (qsocket_t *sock)

-{

-	sfunc.CloseSocket(sock->socket);

-}

-

-

-void Datagram_Listen (qboolean state)

-{

-	int i;

-

-	for (i = 0; i < net_numlandrivers; i++)

-		if (net_landrivers[i].initialized)

-			net_landrivers[i].Listen (state);

-}

-

-

-static qsocket_t *_Datagram_CheckNewConnections (void)

-{

-	struct qsockaddr clientaddr;

-	struct qsockaddr newaddr;

-	int			newsock;

-	int			acceptsock;

-	qsocket_t	*sock;

-	qsocket_t	*s;

-	int			len;

-	int			command;

-	int			control;

-	int			ret;

-

-	acceptsock = dfunc.CheckNewConnections();

-	if (acceptsock == -1)

-		return NULL;

-

-	SZ_Clear(&net_message);

-

-	len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);

-	if (len < sizeof(int))

-		return NULL;

-	net_message.cursize = len;

-

-	MSG_BeginReading ();

-	control = BigLong(*((int *)net_message.data));

-	MSG_ReadLong();

-	if (control == -1)

-		return NULL;

-	if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)

-		return NULL;

-	if ((control & NETFLAG_LENGTH_MASK) != len)

-		return NULL;

-

-	command = MSG_ReadByte();

-	if (command == CCREQ_SERVER_INFO)

-	{

-		if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)

-			return NULL;

-

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREP_SERVER_INFO);

-		dfunc.GetSocketAddr(acceptsock, &newaddr);

-		MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));

-		MSG_WriteString(&net_message, hostname.string);

-		MSG_WriteString(&net_message, sv.name);

-		MSG_WriteByte(&net_message, net_activeconnections);

-		MSG_WriteByte(&net_message, svs.maxclients);

-		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-		SZ_Clear(&net_message);

-		return NULL;

-	}

-

-	if (command == CCREQ_PLAYER_INFO)

-	{

-		int			playerNumber;

-		int			activeNumber;

-		int			clientNumber;

-		client_t	*client;

-		

-		playerNumber = MSG_ReadByte();

-		activeNumber = -1;

-		for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)

-		{

-			if (client->active)

-			{

-				activeNumber++;

-				if (activeNumber == playerNumber)

-					break;

-			}

-		}

-		if (clientNumber == svs.maxclients)

-			return NULL;

-

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);

-		MSG_WriteByte(&net_message, playerNumber);

-		MSG_WriteString(&net_message, client->name);

-		MSG_WriteLong(&net_message, client->colors);

-		MSG_WriteLong(&net_message, (int)client->edict->v.frags);

-		MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));

-		MSG_WriteString(&net_message, client->netconnection->address);

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-		SZ_Clear(&net_message);

-

-		return NULL;

-	}

-

-	if (command == CCREQ_RULE_INFO)

-	{

-		char	*prevCvarName;

-		cvar_t	*var;

-

-		// find the search start location

-		prevCvarName = MSG_ReadString();

-		if (*prevCvarName)

-		{

-			var = Cvar_FindVar (prevCvarName);

-			if (!var)

-				return NULL;

-			var = var->next;

-		}

-		else

-			var = cvar_vars;

-

-		// search for the next server cvar

-		while (var)

-		{

-			if (var->server)

-				break;

-			var = var->next;

-		}

-

-		// send the response

-

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREP_RULE_INFO);

-		if (var)

-		{

-			MSG_WriteString(&net_message, var->name);

-			MSG_WriteString(&net_message, var->string);

-		}

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-		SZ_Clear(&net_message);

-

-		return NULL;

-	}

-

-	if (command != CCREQ_CONNECT)

-		return NULL;

-

-	if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)

-		return NULL;

-

-	if (MSG_ReadByte() != NET_PROTOCOL_VERSION)

-	{

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREP_REJECT);

-		MSG_WriteString(&net_message, "Incompatible version.\n");

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-		SZ_Clear(&net_message);

-		return NULL;

-	}

-

-#ifdef BAN_TEST

-	// check for a ban

-	if (clientaddr.sa_family == AF_INET)

-	{

-		unsigned long testAddr;

-		testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;

-		if ((testAddr & banMask) == banAddr)

-		{

-			SZ_Clear(&net_message);

-			// save space for the header, filled in later

-			MSG_WriteLong(&net_message, 0);

-			MSG_WriteByte(&net_message, CCREP_REJECT);

-			MSG_WriteString(&net_message, "You have been banned.\n");

-			*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-			dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-			SZ_Clear(&net_message);

-			return NULL;

-		}

-	}

-#endif

-

-	// see if this guy is already connected

-	for (s = net_activeSockets; s; s = s->next)

-	{

-		if (s->driver != net_driverlevel)

-			continue;

-		ret = dfunc.AddrCompare(&clientaddr, &s->addr);

-		if (ret >= 0)

-		{

-			// is this a duplicate connection reqeust?

-			if (ret == 0 && net_time - s->connecttime < 2.0)

-			{

-				// yes, so send a duplicate reply

-				SZ_Clear(&net_message);

-				// save space for the header, filled in later

-				MSG_WriteLong(&net_message, 0);

-				MSG_WriteByte(&net_message, CCREP_ACCEPT);

-				dfunc.GetSocketAddr(s->socket, &newaddr);

-				MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));

-				*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-				dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-				SZ_Clear(&net_message);

-				return NULL;

-			}

-			// it's somebody coming back in from a crash/disconnect

-			// so close the old qsocket and let their retry get them back in

-			NET_Close(s);

-			return NULL;

-		}

-	}

-

-	// allocate a QSocket

-	sock = NET_NewQSocket ();

-	if (sock == NULL)

-	{

-		// no room; try to let him know

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREP_REJECT);

-		MSG_WriteString(&net_message, "Server is full.\n");

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-		SZ_Clear(&net_message);

-		return NULL;

-	}

-

-	// allocate a network socket

-	newsock = dfunc.OpenSocket(0);

-	if (newsock == -1)

-	{

-		NET_FreeQSocket(sock);

-		return NULL;

-	}

-

-	// connect to the client

-	if (dfunc.Connect (newsock, &clientaddr) == -1)

-	{

-		dfunc.CloseSocket(newsock);

-		NET_FreeQSocket(sock);

-		return NULL;

-	}

-

-	// everything is allocated, just fill in the details	

-	sock->socket = newsock;

-	sock->landriver = net_landriverlevel;

-	sock->addr = clientaddr;

-	Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr));

-

-	// send him back the info about the server connection he has been allocated

-	SZ_Clear(&net_message);

-	// save space for the header, filled in later

-	MSG_WriteLong(&net_message, 0);

-	MSG_WriteByte(&net_message, CCREP_ACCEPT);

-	dfunc.GetSocketAddr(newsock, &newaddr);

-	MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));

-//	MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));

-	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-	dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);

-	SZ_Clear(&net_message);

-

-	return sock;

-}

-

-qsocket_t *Datagram_CheckNewConnections (void)

-{

-	qsocket_t *ret = NULL;

-

-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)

-		if (net_landrivers[net_landriverlevel].initialized)

-			if ((ret = _Datagram_CheckNewConnections ()) != NULL)

-				break;

-	return ret;

-}

-

-

-static void _Datagram_SearchForHosts (qboolean xmit)

-{

-	int		ret;

-	int		n;

-	int		i;

-	struct qsockaddr readaddr;

-	struct qsockaddr myaddr;

-	int		control;

-

-	dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);

-	if (xmit)

-	{

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);

-		MSG_WriteString(&net_message, "QUAKE");

-		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);

-		SZ_Clear(&net_message);

-	}

-

-	while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)

-	{

-		if (ret < sizeof(int))

-			continue;

-		net_message.cursize = ret;

-

-		// don't answer our own query

-		if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)

-			continue;

-

-		// is the cache full?

-		if (hostCacheCount == HOSTCACHESIZE)

-			continue;

-

-		MSG_BeginReading ();

-		control = BigLong(*((int *)net_message.data));

-		MSG_ReadLong();

-		if (control == -1)

-			continue;

-		if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)

-			continue;

-		if ((control & NETFLAG_LENGTH_MASK) != ret)

-			continue;

-

-		if (MSG_ReadByte() != CCREP_SERVER_INFO)

-			continue;

-

-		dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);

-		// search the cache for this server

-		for (n = 0; n < hostCacheCount; n++)

-			if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)

-				break;

-

-		// is it already there?

-		if (n < hostCacheCount)

-			continue;

-

-		// add it

-		hostCacheCount++;

-		Q_strcpy(hostcache[n].name, MSG_ReadString());

-		Q_strcpy(hostcache[n].map, MSG_ReadString());

-		hostcache[n].users = MSG_ReadByte();

-		hostcache[n].maxusers = MSG_ReadByte();

-		if (MSG_ReadByte() != NET_PROTOCOL_VERSION)

-		{

-			Q_strcpy(hostcache[n].cname, hostcache[n].name);

-			hostcache[n].cname[14] = 0;

-			Q_strcpy(hostcache[n].name, "*");

-			Q_strcat(hostcache[n].name, hostcache[n].cname);

-		}

-		Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));

-		hostcache[n].driver = net_driverlevel;

-		hostcache[n].ldriver = net_landriverlevel;

-		Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));

-

-		// check for a name conflict

-		for (i = 0; i < hostCacheCount; i++)

-		{

-			if (i == n)

-				continue;

-			if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)

-			{

-				i = Q_strlen(hostcache[n].name);

-				if (i < 15 && hostcache[n].name[i-1] > '8')

-				{

-					hostcache[n].name[i] = '0';

-					hostcache[n].name[i+1] = 0;

-				}

-				else

-					hostcache[n].name[i-1]++;

-				i = -1;

-			}

-		}

-	}

-}

-

-void Datagram_SearchForHosts (qboolean xmit)

-{

-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)

-	{

-		if (hostCacheCount == HOSTCACHESIZE)

-			break;

-		if (net_landrivers[net_landriverlevel].initialized)

-			_Datagram_SearchForHosts (xmit);

-	}

-}

-

-

-static qsocket_t *_Datagram_Connect (char *host)

-{

-	struct qsockaddr sendaddr;

-	struct qsockaddr readaddr;

-	qsocket_t	*sock;

-	int			newsock;

-	int			ret;

-	int			reps;

-	double		start_time;

-	int			control;

-	char		*reason;

-

-	// see if we can resolve the host name

-	if (dfunc.GetAddrFromName(host, &sendaddr) == -1)

-		return NULL;

-

-	newsock = dfunc.OpenSocket (0);

-	if (newsock == -1)

-		return NULL;

-

-	sock = NET_NewQSocket ();

-	if (sock == NULL)

-		goto ErrorReturn2;

-	sock->socket = newsock;

-	sock->landriver = net_landriverlevel;

-

-	// connect to the host

-	if (dfunc.Connect (newsock, &sendaddr) == -1)

-		goto ErrorReturn;

-

-	// send the connection request

-	Con_Printf("trying...\n"); SCR_UpdateScreen ();

-	start_time = net_time;

-

-	for (reps = 0; reps < 3; reps++)

-	{

-		SZ_Clear(&net_message);

-		// save space for the header, filled in later

-		MSG_WriteLong(&net_message, 0);

-		MSG_WriteByte(&net_message, CCREQ_CONNECT);

-		MSG_WriteString(&net_message, "QUAKE");

-		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);

-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));

-		dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);

-		SZ_Clear(&net_message);

-		do

-		{

-			ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);

-			// if we got something, validate it

-			if (ret > 0)

-			{

-				// is it from the right place?

-				if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)

-				{

-#ifdef DEBUG

-					Con_Printf("wrong reply address\n");

-					Con_Printf("Expected: %s\n", StrAddr (&sendaddr));

-					Con_Printf("Received: %s\n", StrAddr (&readaddr));

-					SCR_UpdateScreen ();

-#endif

-					ret = 0;

-					continue;

-				}

-

-				if (ret < sizeof(int))

-				{

-					ret = 0;

-					continue;

-				}

-

-				net_message.cursize = ret;

-				MSG_BeginReading ();

-

-				control = BigLong(*((int *)net_message.data));

-				MSG_ReadLong();

-				if (control == -1)

-				{

-					ret = 0;

-					continue;

-				}

-				if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)

-				{

-					ret = 0;

-					continue;

-				}

-				if ((control & NETFLAG_LENGTH_MASK) != ret)

-				{

-					ret = 0;

-					continue;

-				}

-			}

-		}

-		while (ret == 0 && (SetNetTime() - start_time) < 2.5);

-		if (ret)

-			break;

-		Con_Printf("still trying...\n"); SCR_UpdateScreen ();

-		start_time = SetNetTime();

-	}

-

-	if (ret == 0)

-	{

-		reason = "No Response";

-		Con_Printf("%s\n", reason);

-		Q_strcpy(m_return_reason, reason);

-		goto ErrorReturn;

-	}

-

-	if (ret == -1)

-	{

-		reason = "Network Error";

-		Con_Printf("%s\n", reason);

-		Q_strcpy(m_return_reason, reason);

-		goto ErrorReturn;

-	}

-

-	ret = MSG_ReadByte();

-	if (ret == CCREP_REJECT)

-	{

-		reason = MSG_ReadString();

-		Con_Printf(reason);

-		Q_strncpy(m_return_reason, reason, 31);

-		goto ErrorReturn;

-	}

-

-	if (ret == CCREP_ACCEPT)

-	{

-		Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));

-		dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());

-	}

-	else

-	{

-		reason = "Bad Response";

-		Con_Printf("%s\n", reason);

-		Q_strcpy(m_return_reason, reason);

-		goto ErrorReturn;

-	}

-

-	dfunc.GetNameFromAddr (&sendaddr, sock->address);

-

-	Con_Printf ("Connection accepted\n");

-	sock->lastMessageTime = SetNetTime();

-

-	// switch the connection to the specified address

-	if (dfunc.Connect (newsock, &sock->addr) == -1)

-	{

-		reason = "Connect to Game failed";

-		Con_Printf("%s\n", reason);

-		Q_strcpy(m_return_reason, reason);

-		goto ErrorReturn;

-	}

-

-	m_return_onerror = false;

-	return sock;

-

-ErrorReturn:

-	NET_FreeQSocket(sock);

-ErrorReturn2:

-	dfunc.CloseSocket(newsock);

-	if (m_return_onerror)

-	{

-		key_dest = key_menu;

-		m_state = m_return_state;

-		m_return_onerror = false;

-	}

-	return NULL;

-}

-

-qsocket_t *Datagram_Connect (char *host)

-{

-	qsocket_t *ret = NULL;

-

-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)

-		if (net_landrivers[net_landriverlevel].initialized)

-			if ((ret = _Datagram_Connect (host)) != NULL)

-				break;

-	return ret;

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_dgrm.c
+
+// This is enables a simple IP banning mechanism
+#define BAN_TEST
+
+#ifdef BAN_TEST
+#if defined(_WIN32)
+#include <windows.h>
+#elif defined (NeXT)
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#endif	// BAN_TEST
+
+#include "quakedef.h"
+#include "net_dgrm.h"
+
+// these two macros are to make the code more readable
+#define sfunc	net_landrivers[sock->landriver]
+#define dfunc	net_landrivers[net_landriverlevel]
+
+static int net_landriverlevel;
+
+/* statistic counters */
+int	packetsSent = 0;
+int	packetsReSent = 0;
+int packetsReceived = 0;
+int receivedDuplicateCount = 0;
+int shortPacketCount = 0;
+int droppedDatagrams;
+
+static int myDriverLevel;
+
+struct packetBuffer_t
+{
+	unsigned int	length;
+	unsigned int	sequence;
+	byte			data[MAX_DATAGRAM];
+} packetBuffer;
+
+extern int m_return_state;
+extern int m_state;
+extern qboolean m_return_onerror;
+extern char m_return_reason[32];
+
+
+#ifdef DEBUG
+char *StrAddr (struct qsockaddr *addr)
+{
+	static char buf[34];
+	byte *p = (byte *)addr;
+	int n;
+
+	for (n = 0; n < 16; n++)
+		sprintf (buf + n * 2, "%02x", *p++);
+	return buf;
+}
+#endif
+
+
+#ifdef BAN_TEST
+typedef union {
+    unsigned long ul;
+    struct in_addr addr;
+} ulongaddr;
+
+typedef union {
+    qsockaddr q;
+    sockaddr_in i;
+} qsockaddr2sockaddr_in;
+
+unsigned long banAddr = 0x00000000;
+unsigned long banMask = 0xffffffff;
+
+void NET_Ban_f (void)
+{
+	char	addrStr [32];
+	char	maskStr [32];
+	void	(*print) (const char *fmt, ...);
+
+	if (cmd_source == src_command)
+	{
+		if (!sv.active)
+		{
+			Cmd_ForwardToServer ();
+			return;
+		}
+		print = Con_Printf;
+	}
+	else
+	{
+		if (pr_global_struct->deathmatch && !host_client->privileged)
+			return;
+		print = SV_ClientPrintf;
+	}
+
+	switch (Cmd_Argc ())
+	{
+		case 1:
+		{
+		    ulongaddr addrTemp;
+		    addrTemp.ul = banAddr;
+		    ulongaddr maskTemp;
+		    maskTemp.ul - banMask;
+
+			if (addrTemp.addr.s_addr)
+			{
+				Q_strcpy(addrStr, inet_ntoa(addrTemp.addr));
+				Q_strcpy(maskStr, inet_ntoa(maskTemp.addr));
+				print("Banning %s [%s]\n", addrStr, maskStr);
+			}
+			else
+				print("Banning not active\n");
+		}
+        break;
+
+		case 2:
+			if (Q_strcasecmp(Cmd_Argv(1), "off") == 0)
+				banAddr = 0x00000000;
+			else
+				banAddr = inet_addr(Cmd_Argv(1));
+			banMask = 0xffffffff;
+			break;
+
+		case 3:
+			banAddr = inet_addr(Cmd_Argv(1));
+			banMask = inet_addr(Cmd_Argv(2));
+			break;
+
+		default:
+			print("BAN ip_address [mask]\n");
+			break;
+	}
+}
+#endif
+
+
+int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)
+{
+	unsigned int	packetLen;
+	unsigned int	dataLen;
+	unsigned int	eom;
+
+#ifdef DEBUG
+	if (data->cursize == 0)
+		Sys_Error("Datagram_SendMessage: zero length message\n");
+
+	if (data->cursize > NET_MAXMESSAGE)
+		Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);
+
+	if (sock->canSend == false)
+		Sys_Error("SendMessage: called with canSend == false\n");
+#endif
+
+	Q_memcpy(sock->sendMessage, data->data, data->cursize);
+	sock->sendMessageLength = data->cursize;
+
+	if (data->cursize <= MAX_DATAGRAM)
+	{
+		dataLen = data->cursize;
+		eom = NETFLAG_EOM;
+	}
+	else
+	{
+		dataLen = MAX_DATAGRAM;
+		eom = 0;
+	}
+	packetLen = NET_HEADERSIZE + dataLen;
+
+	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
+	packetBuffer.sequence = BigLong(sock->sendSequence++);
+	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
+
+	sock->canSend = false;
+
+	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+		return -1;
+
+	sock->lastSendTime = net_time;
+	packetsSent++;
+	return 1;
+}
+
+
+int SendMessageNext (qsocket_t *sock)
+{
+	unsigned int	packetLen;
+	unsigned int	dataLen;
+	unsigned int	eom;
+
+	if (sock->sendMessageLength <= MAX_DATAGRAM)
+	{
+		dataLen = sock->sendMessageLength;
+		eom = NETFLAG_EOM;
+	}
+	else
+	{
+		dataLen = MAX_DATAGRAM;
+		eom = 0;
+	}
+	packetLen = NET_HEADERSIZE + dataLen;
+
+	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
+	packetBuffer.sequence = BigLong(sock->sendSequence++);
+	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
+
+	sock->sendNext = false;
+
+	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+		return -1;
+
+	sock->lastSendTime = net_time;
+	packetsSent++;
+	return 1;
+}
+
+
+int ReSendMessage (qsocket_t *sock)
+{
+	unsigned int	packetLen;
+	unsigned int	dataLen;
+	unsigned int	eom;
+
+	if (sock->sendMessageLength <= MAX_DATAGRAM)
+	{
+		dataLen = sock->sendMessageLength;
+		eom = NETFLAG_EOM;
+	}
+	else
+	{
+		dataLen = MAX_DATAGRAM;
+		eom = 0;
+	}
+	packetLen = NET_HEADERSIZE + dataLen;
+
+	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
+	packetBuffer.sequence = BigLong(sock->sendSequence - 1);
+	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
+
+	sock->sendNext = false;
+
+	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+		return -1;
+
+	sock->lastSendTime = net_time;
+	packetsReSent++;
+	return 1;
+}
+
+
+qboolean Datagram_CanSendMessage (qsocket_t *sock)
+{
+	if (sock->sendNext)
+		SendMessageNext (sock);
+
+	return sock->canSend;
+}
+
+
+qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock)
+{
+	return true;
+}
+
+
+int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
+{
+	int 	packetLen;
+
+#ifdef DEBUG
+	if (data->cursize == 0)
+		Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");
+
+	if (data->cursize > MAX_DATAGRAM)
+		Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
+#endif
+
+	packetLen = NET_HEADERSIZE + data->cursize;
+
+	packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);
+	packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);
+	Q_memcpy (packetBuffer.data, data->data, data->cursize);
+
+	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+		return -1;
+
+	packetsSent++;
+	return 1;
+}
+
+
+int	Datagram_GetMessage (qsocket_t *sock)
+{
+	unsigned int	length;
+	unsigned int	flags;
+	int				ret = 0;
+	struct qsockaddr readaddr;
+	unsigned int	sequence;
+	unsigned int	count;
+
+	if (!sock->canSend)
+		if ((net_time - sock->lastSendTime) > 1.0)
+			ReSendMessage (sock);
+
+	while(1)
+	{	
+		length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
+
+//	if ((rand() & 255) > 220)
+//		continue;
+
+		if (length == 0)
+			break;
+
+		if (length == (unsigned int) -1)
+		{
+			Con_Printf("Read error\n");
+			return -1;
+		}
+
+		if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)
+		{
+#ifdef DEBUG
+			Con_DPrintf("Forged packet received\n");
+			Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));
+			Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
+#endif
+			continue;
+		}
+
+		if (length < NET_HEADERSIZE)
+		{
+			shortPacketCount++;
+			continue;
+		}
+
+		length = BigLong(packetBuffer.length);
+		flags = length & (~NETFLAG_LENGTH_MASK);
+		length &= NETFLAG_LENGTH_MASK;
+
+		if (flags & NETFLAG_CTL)
+			continue;
+
+		sequence = BigLong(packetBuffer.sequence);
+		packetsReceived++;
+
+		if (flags & NETFLAG_UNRELIABLE)
+		{
+			if (sequence < sock->unreliableReceiveSequence)
+			{
+				Con_DPrintf("Got a stale datagram\n");
+				ret = 0;
+				break;
+			}
+			if (sequence != sock->unreliableReceiveSequence)
+			{
+				count = sequence - sock->unreliableReceiveSequence;
+				droppedDatagrams += count;
+				Con_DPrintf("Dropped %u datagram(s)\n", count);
+			}
+			sock->unreliableReceiveSequence = sequence + 1;
+
+			length -= NET_HEADERSIZE;
+
+			SZ_Clear (&net_message);
+			SZ_Write (&net_message, packetBuffer.data, length);
+
+			ret = 2;
+			break;
+		}
+
+		if (flags & NETFLAG_ACK)
+		{
+			if (sequence != (sock->sendSequence - 1))
+			{
+				Con_DPrintf("Stale ACK received\n");
+				continue;
+			}
+			if (sequence == sock->ackSequence)
+			{
+				sock->ackSequence++;
+				if (sock->ackSequence != sock->sendSequence)
+					Con_DPrintf("ack sequencing error\n");
+			}
+			else
+			{
+				Con_DPrintf("Duplicate ACK received\n");
+				continue;
+			}
+			sock->sendMessageLength -= MAX_DATAGRAM;
+			if (sock->sendMessageLength > 0)
+			{
+				Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
+				sock->sendNext = true;
+			}
+			else
+			{
+				sock->sendMessageLength = 0;
+				sock->canSend = true;
+			}
+			continue;
+		}
+
+		if (flags & NETFLAG_DATA)
+		{
+			packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
+			packetBuffer.sequence = BigLong(sequence);
+			sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);
+
+			if (sequence != sock->receiveSequence)
+			{
+				receivedDuplicateCount++;
+				continue;
+			}
+			sock->receiveSequence++;
+
+			length -= NET_HEADERSIZE;
+
+			if (flags & NETFLAG_EOM)
+			{
+				SZ_Clear(&net_message);
+				SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
+				SZ_Write(&net_message, packetBuffer.data, length);
+				sock->receiveMessageLength = 0;
+
+				ret = 1;
+				break;
+			}
+
+			Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
+			sock->receiveMessageLength += length;
+			continue;
+		}
+	}
+
+	if (sock->sendNext)
+		SendMessageNext (sock);
+
+	return ret;
+}
+
+
+void PrintStats(qsocket_t *s)
+{
+	Con_Printf("canSend = %4u   \n", s->canSend);
+	Con_Printf("sendSeq = %4u   ", s->sendSequence);
+	Con_Printf("recvSeq = %4u   \n", s->receiveSequence);
+	Con_Printf("\n");
+}
+
+void NET_Stats_f (void)
+{
+	qsocket_t	*s;
+
+	if (Cmd_Argc () == 1)
+	{
+		Con_Printf("unreliable messages sent   = %i\n", unreliableMessagesSent);
+		Con_Printf("unreliable messages recv   = %i\n", unreliableMessagesReceived);
+		Con_Printf("reliable messages sent     = %i\n", messagesSent);
+		Con_Printf("reliable messages received = %i\n", messagesReceived);
+		Con_Printf("packetsSent                = %i\n", packetsSent);
+		Con_Printf("packetsReSent              = %i\n", packetsReSent);
+		Con_Printf("packetsReceived            = %i\n", packetsReceived);
+		Con_Printf("receivedDuplicateCount     = %i\n", receivedDuplicateCount);
+		Con_Printf("shortPacketCount           = %i\n", shortPacketCount);
+		Con_Printf("droppedDatagrams           = %i\n", droppedDatagrams);
+	}
+	else if (Q_strcmp(Cmd_Argv(1), "*") == 0)
+	{
+		for (s = net_activeSockets; s; s = s->next)
+			PrintStats(s);
+		for (s = net_freeSockets; s; s = s->next)
+			PrintStats(s);
+	}
+	else
+	{
+		for (s = net_activeSockets; s; s = s->next)
+			if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
+				break;
+		if (s == NULL)
+			for (s = net_freeSockets; s; s = s->next)
+				if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
+					break;
+		if (s == NULL)
+			return;
+		PrintStats(s);
+	}
+}
+
+
+static qboolean testInProgress = false;
+static int		testPollCount;
+static int		testDriver;
+static int		testSocket;
+
+static void Test_Poll(void* arg);
+PollProcedure	testPollProcedure = {NULL, 0.0, Test_Poll, NULL};
+
+static void Test_Poll(void* /* arg */)
+{
+	struct qsockaddr clientaddr;
+	int		control;
+	int		len;
+	char	name[32];
+	char	address[64];
+	int		colors;
+	int		frags;
+	int		connectTime;
+	byte	playerNumber;
+
+	net_landriverlevel = testDriver;
+
+	while (1)
+	{
+		len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
+		if (len < (int) sizeof(int))
+			break;
+
+		net_message.cursize = len;
+
+		MSG_BeginReading ();
+		control = BigLong(*((int *)net_message.data));
+		MSG_ReadLong();
+		if (control == -1)
+			break;
+		if ((control & (~NETFLAG_LENGTH_MASK)) !=  (int) NETFLAG_CTL)
+			break;
+		if ((control & NETFLAG_LENGTH_MASK) != len)
+			break;
+
+		if (MSG_ReadByte() != CCREP_PLAYER_INFO)
+			Sys_Error("Unexpected repsonse to Player Info request\n");
+
+		playerNumber = MSG_ReadByte();
+		Q_strcpy(name, MSG_ReadString());
+		colors = MSG_ReadLong();
+		frags = MSG_ReadLong();
+		connectTime = MSG_ReadLong();
+		Q_strcpy(address, MSG_ReadString());
+
+		Con_Printf("%s\n  frags:%3i  colors:%u %u  time:%u\n  %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);
+	}
+
+	testPollCount--;
+	if (testPollCount)
+	{
+		SchedulePollProcedure(&testPollProcedure, 0.1);
+	}
+	else
+	{
+		dfunc.CloseSocket(testSocket);
+		testInProgress = false;
+	}
+}
+
+static void Test_f (void)
+{
+	char	*host;
+	int		n;
+	int		max = MAX_SCOREBOARD;
+	struct qsockaddr sendaddr;
+
+	if (testInProgress)
+		return;
+
+	host = Cmd_Argv (1);
+
+	if (host && hostCacheCount)
+	{
+		for (n = 0; n < hostCacheCount; n++)
+			if (Q_strcasecmp (host, hostcache[n].name) == 0)
+			{
+				if (hostcache[n].driver != myDriverLevel)
+					continue;
+				net_landriverlevel = hostcache[n].ldriver;
+				max = hostcache[n].maxusers;
+				Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
+				break;
+			}
+		if (n < hostCacheCount)
+			goto JustDoIt;
+	}
+
+	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+	{
+		if (!net_landrivers[net_landriverlevel].initialized)
+			continue;
+
+		// see if we can resolve the host name
+		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
+			break;
+	}
+	if (net_landriverlevel == net_numlandrivers)
+		return;
+
+JustDoIt:
+	testSocket = dfunc.OpenSocket(0);
+	if (testSocket == -1)
+		return;
+
+	testInProgress = true;
+	testPollCount = 20;
+	testDriver = net_landriverlevel;
+
+	for (n = 0; n < max; n++)
+	{
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
+		MSG_WriteByte(&net_message, n);
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | 	(net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
+	}
+	SZ_Clear(&net_message);
+	SchedulePollProcedure(&testPollProcedure, 0.1);
+}
+
+
+static qboolean test2InProgress = false;
+static int		test2Driver;
+static int		test2Socket;
+
+static void Test2_Poll(void*);
+PollProcedure	test2PollProcedure = {NULL, 0.0, Test2_Poll, NULL};
+
+static void Test2_Poll(void* /* arg */)
+{
+	struct qsockaddr clientaddr;
+	int		control;
+	int		len;
+	char	name[256];
+	char	value[256];
+
+	net_landriverlevel = test2Driver;
+	name[0] = 0;
+
+	len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
+	if (len < (int) sizeof(int))
+		goto Reschedule;
+
+	net_message.cursize = len;
+
+	MSG_BeginReading ();
+	control = BigLong(*((int *)net_message.data));
+	MSG_ReadLong();
+	if (control == -1)
+		goto Error;
+	if ((control & (~NETFLAG_LENGTH_MASK)) !=  (int) NETFLAG_CTL)
+		goto Error;
+	if ((control & NETFLAG_LENGTH_MASK) != len)
+		goto Error;
+
+	if (MSG_ReadByte() != CCREP_RULE_INFO)
+		goto Error;
+
+	Q_strcpy(name, MSG_ReadString());
+	if (name[0] == 0)
+		goto Done;
+	Q_strcpy(value, MSG_ReadString());
+
+	Con_Printf("%-16.16s  %-16.16s\n", name, value);
+
+	SZ_Clear(&net_message);
+	// save space for the header, filled in later
+	MSG_WriteLong(&net_message, 0);
+	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
+	MSG_WriteString(&net_message, name);
+	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);
+	SZ_Clear(&net_message);
+
+Reschedule:
+	SchedulePollProcedure(&test2PollProcedure, 0.05);
+	return;
+
+Error:
+	Con_Printf("Unexpected repsonse to Rule Info request\n");
+Done:
+	dfunc.CloseSocket(test2Socket);
+	test2InProgress = false;
+	return;
+}
+
+static void Test2_f (void)
+{
+	char	*host;
+	int		n;
+	struct qsockaddr sendaddr;
+
+	if (test2InProgress)
+		return;
+
+	host = Cmd_Argv (1);
+
+	if (host && hostCacheCount)
+	{
+		for (n = 0; n < hostCacheCount; n++)
+			if (Q_strcasecmp (host, hostcache[n].name) == 0)
+			{
+				if (hostcache[n].driver != myDriverLevel)
+					continue;
+				net_landriverlevel = hostcache[n].ldriver;
+				Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
+				break;
+			}
+		if (n < hostCacheCount)
+			goto JustDoIt;
+	}
+
+	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+	{
+		if (!net_landrivers[net_landriverlevel].initialized)
+			continue;
+
+		// see if we can resolve the host name
+		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
+			break;
+	}
+	if (net_landriverlevel == net_numlandrivers)
+		return;
+
+JustDoIt:
+	test2Socket = dfunc.OpenSocket(0);
+	if (test2Socket == -1)
+		return;
+
+	test2InProgress = true;
+	test2Driver = net_landriverlevel;
+
+	SZ_Clear(&net_message);
+	// save space for the header, filled in later
+	MSG_WriteLong(&net_message, 0);
+	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
+	MSG_WriteString(&net_message, "");
+	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);
+	SZ_Clear(&net_message);
+	SchedulePollProcedure(&test2PollProcedure, 0.05);
+}
+
+
+int Datagram_Init (void)
+{
+	int i;
+	int csock;
+
+	myDriverLevel = net_driverlevel;
+	Cmd_AddCommand ("net_stats", NET_Stats_f);
+
+	if (COM_CheckParm("-nolan"))
+		return -1;
+
+	for (i = 0; i < net_numlandrivers; i++)
+		{
+		csock = net_landrivers[i].Init ();
+		if (csock == -1)
+			continue;
+		net_landrivers[i].initialized = true;
+		net_landrivers[i].controlSock = csock;
+		}
+
+#ifdef BAN_TEST
+	Cmd_AddCommand ("ban", NET_Ban_f);
+#endif
+	Cmd_AddCommand ("test", Test_f);
+	Cmd_AddCommand ("test2", Test2_f);
+
+	return 0;
+}
+
+
+void Datagram_Shutdown (void)
+{
+	int i;
+
+//
+// shutdown the lan drivers
+//
+	for (i = 0; i < net_numlandrivers; i++)
+	{
+		if (net_landrivers[i].initialized)
+		{
+			net_landrivers[i].Shutdown ();
+			net_landrivers[i].initialized = false;
+		}
+	}
+}
+
+
+void Datagram_Close (qsocket_t *sock)
+{
+	sfunc.CloseSocket(sock->socket);
+}
+
+
+void Datagram_Listen (qboolean state)
+{
+	int i;
+
+	for (i = 0; i < net_numlandrivers; i++)
+		if (net_landrivers[i].initialized)
+			net_landrivers[i].Listen (state);
+}
+
+
+static qsocket_t *_Datagram_CheckNewConnections (void)
+{
+	struct qsockaddr clientaddr;
+	struct qsockaddr newaddr;
+	int			newsock;
+	int			acceptsock;
+	qsocket_t	*sock;
+	qsocket_t	*s;
+	int			len;
+	int			command;
+	int			control;
+	int			ret;
+
+	acceptsock = dfunc.CheckNewConnections();
+	if (acceptsock == -1)
+		return NULL;
+
+	SZ_Clear(&net_message);
+
+	len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
+	if (len < (int) sizeof(int))
+		return NULL;
+	net_message.cursize = len;
+
+	MSG_BeginReading ();
+	control = BigLong(*((int *)net_message.data));
+	MSG_ReadLong();
+	if (control == -1)
+		return NULL;
+	if ((control & (~NETFLAG_LENGTH_MASK)) !=  (int) NETFLAG_CTL)
+		return NULL;
+	if ((control & NETFLAG_LENGTH_MASK) != len)
+		return NULL;
+
+	command = MSG_ReadByte();
+	if (command == CCREQ_SERVER_INFO)
+	{
+		if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
+			return NULL;
+
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
+		dfunc.GetSocketAddr(acceptsock, &newaddr);
+		MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
+		MSG_WriteString(&net_message, hostname.string);
+		MSG_WriteString(&net_message, sv.name);
+		MSG_WriteByte(&net_message, net_activeconnections);
+		MSG_WriteByte(&net_message, svs.maxclients);
+		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		SZ_Clear(&net_message);
+		return NULL;
+	}
+
+	if (command == CCREQ_PLAYER_INFO)
+	{
+		int			playerNumber;
+		int			activeNumber;
+		int			clientNumber;
+		client_t	*client;
+		
+		playerNumber = MSG_ReadByte();
+		activeNumber = -1;
+		for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
+		{
+			if (client->active)
+			{
+				activeNumber++;
+				if (activeNumber == playerNumber)
+					break;
+			}
+		}
+		if (clientNumber == svs.maxclients)
+			return NULL;
+
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
+		MSG_WriteByte(&net_message, playerNumber);
+		MSG_WriteString(&net_message, client->name);
+		MSG_WriteLong(&net_message, client->colors);
+		MSG_WriteLong(&net_message, (int)client->edict->u.v.frags);
+		MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
+		MSG_WriteString(&net_message, client->netconnection->address);
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		SZ_Clear(&net_message);
+
+		return NULL;
+	}
+
+	if (command == CCREQ_RULE_INFO)
+	{
+		char	*prevCvarName;
+		cvar_t	*var;
+
+		// find the search start location
+		prevCvarName = MSG_ReadString();
+		if (*prevCvarName)
+		{
+			var = Cvar_FindVar (prevCvarName);
+			if (!var)
+				return NULL;
+			var = var->next;
+		}
+		else
+			var = cvar_vars;
+
+		// search for the next server cvar
+		while (var)
+		{
+			if (var->server)
+				break;
+			var = var->next;
+		}
+
+		// send the response
+
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREP_RULE_INFO);
+		if (var)
+		{
+			MSG_WriteString(&net_message, var->name);
+			MSG_WriteString(&net_message, var->string);
+		}
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		SZ_Clear(&net_message);
+
+		return NULL;
+	}
+
+	if (command != CCREQ_CONNECT)
+		return NULL;
+
+	if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
+		return NULL;
+
+	if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
+	{
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREP_REJECT);
+		MSG_WriteString(&net_message, "Incompatible version.\n");
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		SZ_Clear(&net_message);
+		return NULL;
+	}
+
+#ifdef BAN_TEST
+	// check for a ban
+	if (clientaddr.sa_family == AF_INET)
+	{
+	    qsockaddr2sockaddr_in temp;
+	    temp.q = clientaddr;
+	    unsigned long testAddr = temp.i.sin_addr.s_addr;
+		if ((testAddr & banMask) == banAddr)
+		{
+			SZ_Clear(&net_message);
+			// save space for the header, filled in later
+			MSG_WriteLong(&net_message, 0);
+			MSG_WriteByte(&net_message, CCREP_REJECT);
+			MSG_WriteString(&net_message, "You have been banned.\n");
+			*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+			dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+			SZ_Clear(&net_message);
+			return NULL;
+		}
+	}
+#endif
+
+	// see if this guy is already connected
+	for (s = net_activeSockets; s; s = s->next)
+	{
+		if (s->driver != net_driverlevel)
+			continue;
+		ret = dfunc.AddrCompare(&clientaddr, &s->addr);
+		if (ret >= 0)
+		{
+			// is this a duplicate connection reqeust?
+			if (ret == 0 && net_time - s->connecttime < 2.0)
+			{
+				// yes, so send a duplicate reply
+				SZ_Clear(&net_message);
+				// save space for the header, filled in later
+				MSG_WriteLong(&net_message, 0);
+				MSG_WriteByte(&net_message, CCREP_ACCEPT);
+				dfunc.GetSocketAddr(s->socket, &newaddr);
+				MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
+				*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+				dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+				SZ_Clear(&net_message);
+				return NULL;
+			}
+			// it's somebody coming back in from a crash/disconnect
+			// so close the old qsocket and let their retry get them back in
+			NET_Close(s);
+			return NULL;
+		}
+	}
+
+	// allocate a QSocket
+	sock = NET_NewQSocket ();
+	if (sock == NULL)
+	{
+		// no room; try to let him know
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREP_REJECT);
+		MSG_WriteString(&net_message, "Server is full.\n");
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		SZ_Clear(&net_message);
+		return NULL;
+	}
+
+	// allocate a network socket
+	newsock = dfunc.OpenSocket(0);
+	if (newsock == -1)
+	{
+		NET_FreeQSocket(sock);
+		return NULL;
+	}
+
+	// connect to the client
+	if (dfunc.Connect (newsock, &clientaddr) == -1)
+	{
+		dfunc.CloseSocket(newsock);
+		NET_FreeQSocket(sock);
+		return NULL;
+	}
+
+	// everything is allocated, just fill in the details	
+	sock->socket = newsock;
+	sock->landriver = net_landriverlevel;
+	sock->addr = clientaddr;
+	Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr));
+
+	// send him back the info about the server connection he has been allocated
+	SZ_Clear(&net_message);
+	// save space for the header, filled in later
+	MSG_WriteLong(&net_message, 0);
+	MSG_WriteByte(&net_message, CCREP_ACCEPT);
+	dfunc.GetSocketAddr(newsock, &newaddr);
+	MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
+//	MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
+	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+	dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+	SZ_Clear(&net_message);
+
+	return sock;
+}
+
+qsocket_t *Datagram_CheckNewConnections (void)
+{
+	qsocket_t *ret = NULL;
+
+	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+		if (net_landrivers[net_landriverlevel].initialized)
+			if ((ret = _Datagram_CheckNewConnections ()) != NULL)
+				break;
+	return ret;
+}
+
+
+static void _Datagram_SearchForHosts (qboolean xmit)
+{
+	int		ret;
+	int		n;
+	int		i;
+	struct qsockaddr readaddr;
+	struct qsockaddr myaddr;
+	int		control;
+
+	dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
+	if (xmit)
+	{
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
+		MSG_WriteString(&net_message, "QUAKE");
+		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
+		SZ_Clear(&net_message);
+	}
+
+	while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
+	{
+		if (ret < (int) sizeof(int))
+			continue;
+		net_message.cursize = ret;
+
+		// don't answer our own query
+		if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)
+			continue;
+
+		// is the cache full?
+		if (hostCacheCount == HOSTCACHESIZE)
+			continue;
+
+		MSG_BeginReading ();
+		control = BigLong(*((int *)net_message.data));
+		MSG_ReadLong();
+		if (control == -1)
+			continue;
+		if ((control & (~NETFLAG_LENGTH_MASK)) !=  (int) NETFLAG_CTL)
+			continue;
+		if ((control & NETFLAG_LENGTH_MASK) != ret)
+			continue;
+
+		if (MSG_ReadByte() != CCREP_SERVER_INFO)
+			continue;
+
+		dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
+		// search the cache for this server
+		for (n = 0; n < hostCacheCount; n++)
+			if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)
+				break;
+
+		// is it already there?
+		if (n < hostCacheCount)
+			continue;
+
+		// add it
+		hostCacheCount++;
+		Q_strcpy(hostcache[n].name, MSG_ReadString());
+		Q_strcpy(hostcache[n].map, MSG_ReadString());
+		hostcache[n].users = MSG_ReadByte();
+		hostcache[n].maxusers = MSG_ReadByte();
+		if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
+		{
+			Q_strcpy(hostcache[n].cname, hostcache[n].name);
+			hostcache[n].cname[14] = 0;
+			Q_strcpy(hostcache[n].name, "*");
+			Q_strcat(hostcache[n].name, hostcache[n].cname);
+		}
+		Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));
+		hostcache[n].driver = net_driverlevel;
+		hostcache[n].ldriver = net_landriverlevel;
+		Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));
+
+		// check for a name conflict
+		for (i = 0; i < hostCacheCount; i++)
+		{
+			if (i == n)
+				continue;
+			if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
+			{
+				i = Q_strlen(hostcache[n].name);
+				if (i < 15 && hostcache[n].name[i-1] > '8')
+				{
+					hostcache[n].name[i] = '0';
+					hostcache[n].name[i+1] = 0;
+				}
+				else
+					hostcache[n].name[i-1]++;
+				i = -1;
+			}
+		}
+	}
+}
+
+void Datagram_SearchForHosts (qboolean xmit)
+{
+	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+	{
+		if (hostCacheCount == HOSTCACHESIZE)
+			break;
+		if (net_landrivers[net_landriverlevel].initialized)
+			_Datagram_SearchForHosts (xmit);
+	}
+}
+
+
+static qsocket_t *_Datagram_Connect (const char *host)
+{
+	struct qsockaddr sendaddr;
+	struct qsockaddr readaddr;
+	qsocket_t	*sock;
+	int			newsock;
+	int			ret;
+	int			reps;
+	double		start_time;
+	int			control;
+	const char		*reason;
+
+	// see if we can resolve the host name
+	if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
+		return NULL;
+
+	newsock = dfunc.OpenSocket (0);
+	if (newsock == -1)
+		return NULL;
+
+	sock = NET_NewQSocket ();
+	if (sock == NULL)
+		goto ErrorReturn2;
+	sock->socket = newsock;
+	sock->landriver = net_landriverlevel;
+
+	// connect to the host
+	if (dfunc.Connect (newsock, &sendaddr) == -1)
+		goto ErrorReturn;
+
+	// send the connection request
+	Con_Printf("trying...\n"); SCR_UpdateScreen ();
+	start_time = net_time;
+
+	for (reps = 0; reps < 3; reps++)
+	{
+		SZ_Clear(&net_message);
+		// save space for the header, filled in later
+		MSG_WriteLong(&net_message, 0);
+		MSG_WriteByte(&net_message, CCREQ_CONNECT);
+		MSG_WriteString(&net_message, "QUAKE");
+		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
+		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+		dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
+		SZ_Clear(&net_message);
+		do
+		{
+			ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
+			// if we got something, validate it
+			if (ret > 0)
+			{
+				// is it from the right place?
+				if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)
+				{
+#ifdef DEBUG
+					Con_Printf("wrong reply address\n");
+					Con_Printf("Expected: %s\n", StrAddr (&sendaddr));
+					Con_Printf("Received: %s\n", StrAddr (&readaddr));
+					SCR_UpdateScreen ();
+#endif
+					ret = 0;
+					continue;
+				}
+
+				if (ret < (int) sizeof(int))
+				{
+					ret = 0;
+					continue;
+				}
+
+				net_message.cursize = ret;
+				MSG_BeginReading ();
+
+				control = BigLong(*((int *)net_message.data));
+				MSG_ReadLong();
+				if (control == -1)
+				{
+					ret = 0;
+					continue;
+				}
+				if ((control & (~NETFLAG_LENGTH_MASK)) !=  (int) NETFLAG_CTL)
+				{
+					ret = 0;
+					continue;
+				}
+				if ((control & NETFLAG_LENGTH_MASK) != ret)
+				{
+					ret = 0;
+					continue;
+				}
+			}
+		}
+		while (ret == 0 && (SetNetTime() - start_time) < 2.5);
+		if (ret)
+			break;
+		Con_Printf("still trying...\n"); SCR_UpdateScreen ();
+		start_time = SetNetTime();
+	}
+
+	if (ret == 0)
+	{
+		reason = "No Response";
+		Con_Printf("%s\n", reason);
+		Q_strcpy(m_return_reason, reason);
+		goto ErrorReturn;
+	}
+
+	if (ret == -1)
+	{
+		reason = "Network Error";
+		Con_Printf("%s\n", reason);
+		Q_strcpy(m_return_reason, reason);
+		goto ErrorReturn;
+	}
+
+	ret = MSG_ReadByte();
+	if (ret == CCREP_REJECT)
+	{
+		reason = MSG_ReadString();
+		Con_Printf(reason);
+		Q_strncpy(m_return_reason, reason, 31);
+		goto ErrorReturn;
+	}
+
+	if (ret == CCREP_ACCEPT)
+	{
+		Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
+		dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
+	}
+	else
+	{
+		reason = "Bad Response";
+		Con_Printf("%s\n", reason);
+		Q_strcpy(m_return_reason, reason);
+		goto ErrorReturn;
+	}
+
+	dfunc.GetNameFromAddr (&sendaddr, sock->address);
+
+	Con_Printf ("Connection accepted\n");
+	sock->lastMessageTime = SetNetTime();
+
+	// switch the connection to the specified address
+	if (dfunc.Connect (newsock, &sock->addr) == -1)
+	{
+		reason = "Connect to Game failed";
+		Con_Printf("%s\n", reason);
+		Q_strcpy(m_return_reason, reason);
+		goto ErrorReturn;
+	}
+
+	m_return_onerror = false;
+	return sock;
+
+ErrorReturn:
+	NET_FreeQSocket(sock);
+ErrorReturn2:
+	dfunc.CloseSocket(newsock);
+	if (m_return_onerror)
+	{
+		key_dest = key_menu;
+		m_state = m_return_state;
+		m_return_onerror = false;
+	}
+	return NULL;
+}
+
+qsocket_t *Datagram_Connect (const char *host)
+{
+	qsocket_t *ret = NULL;
+
+	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+		if (net_landrivers[net_landriverlevel].initialized)
+			if ((ret = _Datagram_Connect (host)) != NULL)
+				break;
+	return ret;
+}
diff --git a/quake/src/WinQuake/net_dgrm.h b/quake/src/WinQuake/net_dgrm.h
index aa3c715..f55b37e 100644
--- a/quake/src/WinQuake/net_dgrm.h
+++ b/quake/src/WinQuake/net_dgrm.h
@@ -1,34 +1,34 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_dgrm.h

-

-

-int			Datagram_Init (void);

-void		Datagram_Listen (qboolean state);

-void		Datagram_SearchForHosts (qboolean xmit);

-qsocket_t	*Datagram_Connect (char *host);

-qsocket_t 	*Datagram_CheckNewConnections (void);

-int			Datagram_GetMessage (qsocket_t *sock);

-int			Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data);

-int			Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);

-qboolean	Datagram_CanSendMessage (qsocket_t *sock);

-qboolean	Datagram_CanSendUnreliableMessage (qsocket_t *sock);

-void		Datagram_Close (qsocket_t *sock);

-void		Datagram_Shutdown (void);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_dgrm.h
+
+
+int			Datagram_Init (void);
+void		Datagram_Listen (qboolean state);
+void		Datagram_SearchForHosts (qboolean xmit);
+qsocket_t	*Datagram_Connect (const char *host);
+qsocket_t 	*Datagram_CheckNewConnections (void);
+int			Datagram_GetMessage (qsocket_t *sock);
+int			Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data);
+int			Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
+qboolean	Datagram_CanSendMessage (qsocket_t *sock);
+qboolean	Datagram_CanSendUnreliableMessage (qsocket_t *sock);
+void		Datagram_Close (qsocket_t *sock);
+void		Datagram_Shutdown (void);
diff --git a/quake/src/WinQuake/net_dos.c b/quake/src/WinQuake/net_dos.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_dos.c
rename to quake/src/WinQuake/net_dos.cpp
diff --git a/quake/src/WinQuake/net_ipx.c b/quake/src/WinQuake/net_ipx.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_ipx.c
rename to quake/src/WinQuake/net_ipx.cpp
diff --git a/quake/src/WinQuake/net_loop.c b/quake/src/WinQuake/net_loop.cpp
old mode 100644
new mode 100755
similarity index 98%
rename from quake/src/WinQuake/net_loop.c
rename to quake/src/WinQuake/net_loop.cpp
index 4a2719e..54be3e3
--- a/quake/src/WinQuake/net_loop.c
+++ b/quake/src/WinQuake/net_loop.cpp
@@ -1,245 +1,245 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_loop.c

-

-#include "quakedef.h"

-#include "net_loop.h"

-

-qboolean	localconnectpending = false;

-qsocket_t	*loop_client = NULL;

-qsocket_t	*loop_server = NULL;

-

-int Loop_Init (void)

-{

-	if (cls.state == ca_dedicated)

-		return -1;

-	return 0;

-}

-

-

-void Loop_Shutdown (void)

-{

-}

-

-

-void Loop_Listen (qboolean state)

-{

-}

-

-

-void Loop_SearchForHosts (qboolean xmit)

-{

-	if (!sv.active)

-		return;

-

-	hostCacheCount = 1;

-	if (Q_strcmp(hostname.string, "UNNAMED") == 0)

-		Q_strcpy(hostcache[0].name, "local");

-	else

-		Q_strcpy(hostcache[0].name, hostname.string);

-	Q_strcpy(hostcache[0].map, sv.name);

-	hostcache[0].users = net_activeconnections;

-	hostcache[0].maxusers = svs.maxclients;

-	hostcache[0].driver = net_driverlevel;

-	Q_strcpy(hostcache[0].cname, "local");

-}

-

-

-qsocket_t *Loop_Connect (char *host)

-{

-	if (Q_strcmp(host,"local") != 0)

-		return NULL;

-	

-	localconnectpending = true;

-

-	if (!loop_client)

-	{

-		if ((loop_client = NET_NewQSocket ()) == NULL)

-		{

-			Con_Printf("Loop_Connect: no qsocket available\n");

-			return NULL;

-		}

-		Q_strcpy (loop_client->address, "localhost");

-	}

-	loop_client->receiveMessageLength = 0;

-	loop_client->sendMessageLength = 0;

-	loop_client->canSend = true;

-

-	if (!loop_server)

-	{

-		if ((loop_server = NET_NewQSocket ()) == NULL)

-		{

-			Con_Printf("Loop_Connect: no qsocket available\n");

-			return NULL;

-		}

-		Q_strcpy (loop_server->address, "LOCAL");

-	}

-	loop_server->receiveMessageLength = 0;

-	loop_server->sendMessageLength = 0;

-	loop_server->canSend = true;

-

-	loop_client->driverdata = (void *)loop_server;

-	loop_server->driverdata = (void *)loop_client;

-	

-	return loop_client;	

-}

-

-

-qsocket_t *Loop_CheckNewConnections (void)

-{

-	if (!localconnectpending)

-		return NULL;

-

-	localconnectpending = false;

-	loop_server->sendMessageLength = 0;

-	loop_server->receiveMessageLength = 0;

-	loop_server->canSend = true;

-	loop_client->sendMessageLength = 0;

-	loop_client->receiveMessageLength = 0;

-	loop_client->canSend = true;

-	return loop_server;

-}

-

-

-static int IntAlign(int value)

-{

-	return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));

-}

-

-

-int Loop_GetMessage (qsocket_t *sock)

-{

-	int		ret;

-	int		length;

-

-	if (sock->receiveMessageLength == 0)

-		return 0;

-

-	ret = sock->receiveMessage[0];

-	length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);

-	// alignment byte skipped here

-	SZ_Clear (&net_message);

-	SZ_Write (&net_message, &sock->receiveMessage[4], length);

-

-	length = IntAlign(length + 4);

-	sock->receiveMessageLength -= length;

-

-	if (sock->receiveMessageLength)

-		Q_memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength);

-

-	if (sock->driverdata && ret == 1)

-		((qsocket_t *)sock->driverdata)->canSend = true;

-

-	return ret;

-}

-

-

-int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data)

-{

-	byte *buffer;

-	int  *bufferLength;

-

-	if (!sock->driverdata)

-		return -1;

-

-	bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;

-

-	if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE)

-		Sys_Error("Loop_SendMessage: overflow\n");

-

-	buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;

-

-	// message type

-	*buffer++ = 1;

-

-	// length

-	*buffer++ = data->cursize & 0xff;

-	*buffer++ = data->cursize >> 8;

-

-	// align

-	buffer++;

-

-	// message

-	Q_memcpy(buffer, data->data, data->cursize);

-	*bufferLength = IntAlign(*bufferLength + data->cursize + 4);

-

-	sock->canSend = false;

-	return 1;

-}

-

-

-int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)

-{

-	byte *buffer;

-	int  *bufferLength;

-

-	if (!sock->driverdata)

-		return -1;

-

-	bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;

-

-	if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE)

-		return 0;

-

-	buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;

-

-	// message type

-	*buffer++ = 2;

-

-	// length

-	*buffer++ = data->cursize & 0xff;

-	*buffer++ = data->cursize >> 8;

-

-	// align

-	buffer++;

-

-	// message

-	Q_memcpy(buffer, data->data, data->cursize);

-	*bufferLength = IntAlign(*bufferLength + data->cursize + 4);

-	return 1;

-}

-

-

-qboolean Loop_CanSendMessage (qsocket_t *sock)

-{

-	if (!sock->driverdata)

-		return false;

-	return sock->canSend;

-}

-

-

-qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock)

-{

-	return true;

-}

-

-

-void Loop_Close (qsocket_t *sock)

-{

-	if (sock->driverdata)

-		((qsocket_t *)sock->driverdata)->driverdata = NULL;

-	sock->receiveMessageLength = 0;

-	sock->sendMessageLength = 0;

-	sock->canSend = true;

-	if (sock == loop_client)

-		loop_client = NULL;

-	else

-		loop_server = NULL;

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_loop.c
+
+#include "quakedef.h"
+#include "net_loop.h"
+
+qboolean	localconnectpending = false;
+qsocket_t	*loop_client = NULL;
+qsocket_t	*loop_server = NULL;
+
+int Loop_Init (void)
+{
+	if (cls.state == ca_dedicated)
+		return -1;
+	return 0;
+}
+
+
+void Loop_Shutdown (void)
+{
+}
+
+
+void Loop_Listen (qboolean state)
+{
+}
+
+
+void Loop_SearchForHosts (qboolean xmit)
+{
+	if (!sv.active)
+		return;
+
+	hostCacheCount = 1;
+	if (Q_strcmp(hostname.string, "UNNAMED") == 0)
+		Q_strcpy(hostcache[0].name, "local");
+	else
+		Q_strcpy(hostcache[0].name, hostname.string);
+	Q_strcpy(hostcache[0].map, sv.name);
+	hostcache[0].users = net_activeconnections;
+	hostcache[0].maxusers = svs.maxclients;
+	hostcache[0].driver = net_driverlevel;
+	Q_strcpy(hostcache[0].cname, "local");
+}
+
+
+qsocket_t *Loop_Connect (const char *host)
+{
+	if (Q_strcmp(host,"local") != 0)
+		return NULL;
+	
+	localconnectpending = true;
+
+	if (!loop_client)
+	{
+		if ((loop_client = NET_NewQSocket ()) == NULL)
+		{
+			Con_Printf("Loop_Connect: no qsocket available\n");
+			return NULL;
+		}
+		Q_strcpy (loop_client->address, "localhost");
+	}
+	loop_client->receiveMessageLength = 0;
+	loop_client->sendMessageLength = 0;
+	loop_client->canSend = true;
+
+	if (!loop_server)
+	{
+		if ((loop_server = NET_NewQSocket ()) == NULL)
+		{
+			Con_Printf("Loop_Connect: no qsocket available\n");
+			return NULL;
+		}
+		Q_strcpy (loop_server->address, "LOCAL");
+	}
+	loop_server->receiveMessageLength = 0;
+	loop_server->sendMessageLength = 0;
+	loop_server->canSend = true;
+
+	loop_client->driverdata = (void *)loop_server;
+	loop_server->driverdata = (void *)loop_client;
+	
+	return loop_client;	
+}
+
+
+qsocket_t *Loop_CheckNewConnections (void)
+{
+	if (!localconnectpending)
+		return NULL;
+
+	localconnectpending = false;
+	loop_server->sendMessageLength = 0;
+	loop_server->receiveMessageLength = 0;
+	loop_server->canSend = true;
+	loop_client->sendMessageLength = 0;
+	loop_client->receiveMessageLength = 0;
+	loop_client->canSend = true;
+	return loop_server;
+}
+
+
+static int IntAlign(int value)
+{
+	return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));
+}
+
+
+int Loop_GetMessage (qsocket_t *sock)
+{
+	int		ret;
+	int		length;
+
+	if (sock->receiveMessageLength == 0)
+		return 0;
+
+	ret = sock->receiveMessage[0];
+	length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);
+	// alignment byte skipped here
+	SZ_Clear (&net_message);
+	SZ_Write (&net_message, &sock->receiveMessage[4], length);
+
+	length = IntAlign(length + 4);
+	sock->receiveMessageLength -= length;
+
+	if (sock->receiveMessageLength)
+		Q_memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength);
+
+	if (sock->driverdata && ret == 1)
+		((qsocket_t *)sock->driverdata)->canSend = true;
+
+	return ret;
+}
+
+
+int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data)
+{
+	byte *buffer;
+	int  *bufferLength;
+
+	if (!sock->driverdata)
+		return -1;
+
+	bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
+
+	if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE)
+		Sys_Error("Loop_SendMessage: overflow\n");
+
+	buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
+
+	// message type
+	*buffer++ = 1;
+
+	// length
+	*buffer++ = data->cursize & 0xff;
+	*buffer++ = data->cursize >> 8;
+
+	// align
+	buffer++;
+
+	// message
+	Q_memcpy(buffer, data->data, data->cursize);
+	*bufferLength = IntAlign(*bufferLength + data->cursize + 4);
+
+	sock->canSend = false;
+	return 1;
+}
+
+
+int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
+{
+	byte *buffer;
+	int  *bufferLength;
+
+	if (!sock->driverdata)
+		return -1;
+
+	bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
+
+	if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE)
+		return 0;
+
+	buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
+
+	// message type
+	*buffer++ = 2;
+
+	// length
+	*buffer++ = data->cursize & 0xff;
+	*buffer++ = data->cursize >> 8;
+
+	// align
+	buffer++;
+
+	// message
+	Q_memcpy(buffer, data->data, data->cursize);
+	*bufferLength = IntAlign(*bufferLength + data->cursize + 4);
+	return 1;
+}
+
+
+qboolean Loop_CanSendMessage (qsocket_t *sock)
+{
+	if (!sock->driverdata)
+		return false;
+	return sock->canSend;
+}
+
+
+qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock)
+{
+	return true;
+}
+
+
+void Loop_Close (qsocket_t *sock)
+{
+	if (sock->driverdata)
+		((qsocket_t *)sock->driverdata)->driverdata = NULL;
+	sock->receiveMessageLength = 0;
+	sock->sendMessageLength = 0;
+	sock->canSend = true;
+	if (sock == loop_client)
+		loop_client = NULL;
+	else
+		loop_server = NULL;
+}
diff --git a/quake/src/WinQuake/net_loop.h b/quake/src/WinQuake/net_loop.h
index 210f40d..c61be4c 100644
--- a/quake/src/WinQuake/net_loop.h
+++ b/quake/src/WinQuake/net_loop.h
@@ -1,33 +1,33 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_loop.h

-

-int			Loop_Init (void);

-void		Loop_Listen (qboolean state);

-void		Loop_SearchForHosts (qboolean xmit);

-qsocket_t 	*Loop_Connect (char *host);

-qsocket_t 	*Loop_CheckNewConnections (void);

-int			Loop_GetMessage (qsocket_t *sock);

-int			Loop_SendMessage (qsocket_t *sock, sizebuf_t *data);

-int			Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);

-qboolean	Loop_CanSendMessage (qsocket_t *sock);

-qboolean	Loop_CanSendUnreliableMessage (qsocket_t *sock);

-void		Loop_Close (qsocket_t *sock);

-void		Loop_Shutdown (void);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_loop.h
+
+int			Loop_Init (void);
+void		Loop_Listen (qboolean state);
+void		Loop_SearchForHosts (qboolean xmit);
+qsocket_t 	*Loop_Connect (const char *host);
+qsocket_t 	*Loop_CheckNewConnections (void);
+int			Loop_GetMessage (qsocket_t *sock);
+int			Loop_SendMessage (qsocket_t *sock, sizebuf_t *data);
+int			Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
+qboolean	Loop_CanSendMessage (qsocket_t *sock);
+qboolean	Loop_CanSendUnreliableMessage (qsocket_t *sock);
+void		Loop_Close (qsocket_t *sock);
+void		Loop_Shutdown (void);
diff --git a/quake/src/WinQuake/net_main.c b/quake/src/WinQuake/net_main.cpp
old mode 100644
new mode 100755
similarity index 94%
rename from quake/src/WinQuake/net_main.c
rename to quake/src/WinQuake/net_main.cpp
index 4836ab5..21b24fc
--- a/quake/src/WinQuake/net_main.c
+++ b/quake/src/WinQuake/net_main.cpp
@@ -1,997 +1,997 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_main.c

-

-#include "quakedef.h"

-#include "net_vcr.h"

-

-qsocket_t	*net_activeSockets = NULL;

-qsocket_t	*net_freeSockets = NULL;

-int			net_numsockets = 0;

-

-qboolean	serialAvailable = false;

-qboolean	ipxAvailable = false;

-qboolean	tcpipAvailable = false;

-

-int			net_hostport;

-int			DEFAULTnet_hostport = 26000;

-

-char		my_ipx_address[NET_NAMELEN];

-char		my_tcpip_address[NET_NAMELEN];

-

-void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);

-void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);

-void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);

-void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);

-

-static qboolean	listening = false;

-

-qboolean	slistInProgress = false;

-qboolean	slistSilent = false;

-qboolean	slistLocal = true;

-static double	slistStartTime;

-static int		slistLastShown;

-

-static void Slist_Send(void);

-static void Slist_Poll(void);

-PollProcedure	slistSendProcedure = {NULL, 0.0, Slist_Send};

-PollProcedure	slistPollProcedure = {NULL, 0.0, Slist_Poll};

-

-

-sizebuf_t		net_message;

-int				net_activeconnections = 0;

-

-int messagesSent = 0;

-int messagesReceived = 0;

-int unreliableMessagesSent = 0;

-int unreliableMessagesReceived = 0;

-

-cvar_t	net_messagetimeout = {"net_messagetimeout","300"};

-cvar_t	hostname = {"hostname", "UNNAMED"};

-

-qboolean	configRestored = false;

-cvar_t	config_com_port = {"_config_com_port", "0x3f8", true};

-cvar_t	config_com_irq = {"_config_com_irq", "4", true};

-cvar_t	config_com_baud = {"_config_com_baud", "57600", true};

-cvar_t	config_com_modem = {"_config_com_modem", "1", true};

-cvar_t	config_modem_dialtype = {"_config_modem_dialtype", "T", true};

-cvar_t	config_modem_clear = {"_config_modem_clear", "ATZ", true};

-cvar_t	config_modem_init = {"_config_modem_init", "", true};

-cvar_t	config_modem_hangup = {"_config_modem_hangup", "AT H", true};

-

-#ifdef IDGODS

-cvar_t	idgods = {"idgods", "0"};

-#endif

-

-int	vcrFile = -1;

-qboolean recording = false;

-

-// these two macros are to make the code more readable

-#define sfunc	net_drivers[sock->driver]

-#define dfunc	net_drivers[net_driverlevel]

-

-int	net_driverlevel;

-

-

-double			net_time;

-

-double SetNetTime(void)

-{

-	net_time = Sys_FloatTime();

-	return net_time;

-}

-

-

-/*

-===================

-NET_NewQSocket

-

-Called by drivers when a new communications endpoint is required

-The sequence and buffer fields will be filled in properly

-===================

-*/

-qsocket_t *NET_NewQSocket (void)

-{

-	qsocket_t	*sock;

-

-	if (net_freeSockets == NULL)

-		return NULL;

-

-	if (net_activeconnections >= svs.maxclients)

-		return NULL;

-

-	// get one from free list

-	sock = net_freeSockets;

-	net_freeSockets = sock->next;

-

-	// add it to active list

-	sock->next = net_activeSockets;

-	net_activeSockets = sock;

-

-	sock->disconnected = false;

-	sock->connecttime = net_time;

-	Q_strcpy (sock->address,"UNSET ADDRESS");

-	sock->driver = net_driverlevel;

-	sock->socket = 0;

-	sock->driverdata = NULL;

-	sock->canSend = true;

-	sock->sendNext = false;

-	sock->lastMessageTime = net_time;

-	sock->ackSequence = 0;

-	sock->sendSequence = 0;

-	sock->unreliableSendSequence = 0;

-	sock->sendMessageLength = 0;

-	sock->receiveSequence = 0;

-	sock->unreliableReceiveSequence = 0;

-	sock->receiveMessageLength = 0;

-

-	return sock;

-}

-

-

-void NET_FreeQSocket(qsocket_t *sock)

-{

-	qsocket_t	*s;

-

-	// remove it from active list

-	if (sock == net_activeSockets)

-		net_activeSockets = net_activeSockets->next;

-	else

-	{

-		for (s = net_activeSockets; s; s = s->next)

-			if (s->next == sock)

-			{

-				s->next = sock->next;

-				break;

-			}

-		if (!s)

-			Sys_Error ("NET_FreeQSocket: not active\n");

-	}

-

-	// add it to free list

-	sock->next = net_freeSockets;

-	net_freeSockets = sock;

-	sock->disconnected = true;

-}

-

-

-static void NET_Listen_f (void)

-{

-	if (Cmd_Argc () != 2)

-	{

-		Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);

-		return;

-	}

-

-	listening = Q_atoi(Cmd_Argv(1)) ? true : false;

-

-	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)

-	{

-		if (net_drivers[net_driverlevel].initialized == false)

-			continue;

-		dfunc.Listen (listening);

-	}

-}

-

-

-static void MaxPlayers_f (void)

-{

-	int 	n;

-

-	if (Cmd_Argc () != 2)

-	{

-		Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);

-		return;

-	}

-

-	if (sv.active)

-	{

-		Con_Printf ("maxplayers can not be changed while a server is running.\n");

-		return;

-	}

-

-	n = Q_atoi(Cmd_Argv(1));

-	if (n < 1)

-		n = 1;

-	if (n > svs.maxclientslimit)

-	{

-		n = svs.maxclientslimit;

-		Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);

-	}

-

-	if ((n == 1) && listening)

-		Cbuf_AddText ("listen 0\n");

-

-	if ((n > 1) && (!listening))

-		Cbuf_AddText ("listen 1\n");

-

-	svs.maxclients = n;

-	if (n == 1)

-		Cvar_Set ("deathmatch", "0");

-	else

-		Cvar_Set ("deathmatch", "1");

-}

-

-

-static void NET_Port_f (void)

-{

-	int 	n;

-

-	if (Cmd_Argc () != 2)

-	{

-		Con_Printf ("\"port\" is \"%u\"\n", net_hostport);

-		return;

-	}

-

-	n = Q_atoi(Cmd_Argv(1));

-	if (n < 1 || n > 65534)

-	{

-		Con_Printf ("Bad value, must be between 1 and 65534\n");

-		return;

-	}

-

-	DEFAULTnet_hostport = n;

-	net_hostport = n;

-

-	if (listening)

-	{

-		// force a change to the new port

-		Cbuf_AddText ("listen 0\n");

-		Cbuf_AddText ("listen 1\n");

-	}

-}

-

-

-static void PrintSlistHeader(void)

-{

-	Con_Printf("Server          Map             Users\n");

-	Con_Printf("--------------- --------------- -----\n");

-	slistLastShown = 0;

-}

-

-

-static void PrintSlist(void)

-{

-	int n;

-

-	for (n = slistLastShown; n < hostCacheCount; n++)

-	{

-		if (hostcache[n].maxusers)

-			Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);

-		else

-			Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);

-	}

-	slistLastShown = n;

-}

-

-

-static void PrintSlistTrailer(void)

-{

-	if (hostCacheCount)

-		Con_Printf("== end list ==\n\n");

-	else

-		Con_Printf("No Quake servers found.\n\n");

-}

-

-

-void NET_Slist_f (void)

-{

-	if (slistInProgress)

-		return;

-

-	if (! slistSilent)

-	{

-		Con_Printf("Looking for Quake servers...\n");

-		PrintSlistHeader();

-	}

-

-	slistInProgress = true;

-	slistStartTime = Sys_FloatTime();

-

-	SchedulePollProcedure(&slistSendProcedure, 0.0);

-	SchedulePollProcedure(&slistPollProcedure, 0.1);

-

-	hostCacheCount = 0;

-}

-

-

-static void Slist_Send(void)

-{

-	for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)

-	{

-		if (!slistLocal && net_driverlevel == 0)

-			continue;

-		if (net_drivers[net_driverlevel].initialized == false)

-			continue;

-		dfunc.SearchForHosts (true);

-	}

-

-	if ((Sys_FloatTime() - slistStartTime) < 0.5)

-		SchedulePollProcedure(&slistSendProcedure, 0.75);

-}

-

-

-static void Slist_Poll(void)

-{

-	for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)

-	{

-		if (!slistLocal && net_driverlevel == 0)

-			continue;

-		if (net_drivers[net_driverlevel].initialized == false)

-			continue;

-		dfunc.SearchForHosts (false);

-	}

-

-	if (! slistSilent)

-		PrintSlist();

-

-	if ((Sys_FloatTime() - slistStartTime) < 1.5)

-	{

-		SchedulePollProcedure(&slistPollProcedure, 0.1);

-		return;

-	}

-

-	if (! slistSilent)

-		PrintSlistTrailer();

-	slistInProgress = false;

-	slistSilent = false;

-	slistLocal = true;

-}

-

-

-/*

-===================

-NET_Connect

-===================

-*/

-

-int hostCacheCount = 0;

-hostcache_t hostcache[HOSTCACHESIZE];

-

-qsocket_t *NET_Connect (char *host)

-{

-	qsocket_t		*ret;

-	int				n;

-	int				numdrivers = net_numdrivers;

-

-	SetNetTime();

-

-	if (host && *host == 0)

-		host = NULL;

-

-	if (host)

-	{

-		if (Q_strcasecmp (host, "local") == 0)

-		{

-			numdrivers = 1;

-			goto JustDoIt;

-		}

-

-		if (hostCacheCount)

-		{

-			for (n = 0; n < hostCacheCount; n++)

-				if (Q_strcasecmp (host, hostcache[n].name) == 0)

-				{

-					host = hostcache[n].cname;

-					break;

-				}

-			if (n < hostCacheCount)

-				goto JustDoIt;

-		}

-	}

-

-	slistSilent = host ? true : false;

-	NET_Slist_f ();

-

-	while(slistInProgress)

-		NET_Poll();

-

-	if (host == NULL)

-	{

-		if (hostCacheCount != 1)

-			return NULL;

-		host = hostcache[0].cname;

-		Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);

-	}

-

-	if (hostCacheCount)

-		for (n = 0; n < hostCacheCount; n++)

-			if (Q_strcasecmp (host, hostcache[n].name) == 0)

-			{

-				host = hostcache[n].cname;

-				break;

-			}

-

-JustDoIt:

-	for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)

-	{

-		if (net_drivers[net_driverlevel].initialized == false)

-			continue;

-		ret = dfunc.Connect (host);

-		if (ret)

-			return ret;

-	}

-

-	if (host)

-	{

-		Con_Printf("\n");

-		PrintSlistHeader();

-		PrintSlist();

-		PrintSlistTrailer();

-	}

-	

-	return NULL;

-}

-

-

-/*

-===================

-NET_CheckNewConnections

-===================

-*/

-

-struct

-{

-	double	time;

-	int		op;

-	long	session;

-} vcrConnect;

-

-qsocket_t *NET_CheckNewConnections (void)

-{

-	qsocket_t	*ret;

-

-	SetNetTime();

-

-	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)

-	{

-		if (net_drivers[net_driverlevel].initialized == false)

-			continue;

-		if (net_driverlevel && listening == false)

-			continue;

-		ret = dfunc.CheckNewConnections ();

-		if (ret)

-		{

-			if (recording)

-			{

-				vcrConnect.time = host_time;

-				vcrConnect.op = VCR_OP_CONNECT;

-				vcrConnect.session = (long)ret;

-				Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));

-				Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);

-			}

-			return ret;

-		}

-	}

-	

-	if (recording)

-	{

-		vcrConnect.time = host_time;

-		vcrConnect.op = VCR_OP_CONNECT;

-		vcrConnect.session = 0;

-		Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));

-	}

-

-	return NULL;

-}

-

-/*

-===================

-NET_Close

-===================

-*/

-void NET_Close (qsocket_t *sock)

-{

-	if (!sock)

-		return;

-

-	if (sock->disconnected)

-		return;

-

-	SetNetTime();

-

-	// call the driver_Close function

-	sfunc.Close (sock);

-

-	NET_FreeQSocket(sock);

-}

-

-

-/*

-=================

-NET_GetMessage

-

-If there is a complete message, return it in net_message

-

-returns 0 if no data is waiting

-returns 1 if a message was received

-returns -1 if connection is invalid

-=================

-*/

-

-struct

-{

-	double	time;

-	int		op;

-	long	session;

-	int		ret;

-	int		len;

-} vcrGetMessage;

-

-extern void PrintStats(qsocket_t *s);

-

-int	NET_GetMessage (qsocket_t *sock)

-{

-	int ret;

-

-	if (!sock)

-		return -1;

-

-	if (sock->disconnected)

-	{

-		Con_Printf("NET_GetMessage: disconnected socket\n");

-		return -1;

-	}

-

-	SetNetTime();

-

-	ret = sfunc.QGetMessage(sock);

-

-	// see if this connection has timed out

-	if (ret == 0 && sock->driver)

-	{

-		if (net_time - sock->lastMessageTime > net_messagetimeout.value)

-		{

-			NET_Close(sock);

-			return -1;

-		}

-	}

-

-

-	if (ret > 0)

-	{

-		if (sock->driver)

-		{

-			sock->lastMessageTime = net_time;

-			if (ret == 1)

-				messagesReceived++;

-			else if (ret == 2)

-				unreliableMessagesReceived++;

-		}

-

-		if (recording)

-		{

-			vcrGetMessage.time = host_time;

-			vcrGetMessage.op = VCR_OP_GETMESSAGE;

-			vcrGetMessage.session = (long)sock;

-			vcrGetMessage.ret = ret;

-			vcrGetMessage.len = net_message.cursize;

-			Sys_FileWrite (vcrFile, &vcrGetMessage, 24);

-			Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);

-		}

-	}

-	else

-	{

-		if (recording)

-		{

-			vcrGetMessage.time = host_time;

-			vcrGetMessage.op = VCR_OP_GETMESSAGE;

-			vcrGetMessage.session = (long)sock;

-			vcrGetMessage.ret = ret;

-			Sys_FileWrite (vcrFile, &vcrGetMessage, 20);

-		}

-	}

-

-	return ret;

-}

-

-

-/*

-==================

-NET_SendMessage

-

-Try to send a complete length+message unit over the reliable stream.

-returns 0 if the message cannot be delivered reliably, but the connection

-		is still considered valid

-returns 1 if the message was sent properly

-returns -1 if the connection died

-==================

-*/

-struct

-{

-	double	time;

-	int		op;

-	long	session;

-	int		r;

-} vcrSendMessage;

-

-int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)

-{

-	int		r;

-	

-	if (!sock)

-		return -1;

-

-	if (sock->disconnected)

-	{

-		Con_Printf("NET_SendMessage: disconnected socket\n");

-		return -1;

-	}

-

-	SetNetTime();

-	r = sfunc.QSendMessage(sock, data);

-	if (r == 1 && sock->driver)

-		messagesSent++;

-

-	if (recording)

-	{

-		vcrSendMessage.time = host_time;

-		vcrSendMessage.op = VCR_OP_SENDMESSAGE;

-		vcrSendMessage.session = (long)sock;

-		vcrSendMessage.r = r;

-		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);

-	}

-	

-	return r;

-}

-

-

-int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)

-{

-	int		r;

-	

-	if (!sock)

-		return -1;

-

-	if (sock->disconnected)

-	{

-		Con_Printf("NET_SendMessage: disconnected socket\n");

-		return -1;

-	}

-

-	SetNetTime();

-	r = sfunc.SendUnreliableMessage(sock, data);

-	if (r == 1 && sock->driver)

-		unreliableMessagesSent++;

-

-	if (recording)

-	{

-		vcrSendMessage.time = host_time;

-		vcrSendMessage.op = VCR_OP_SENDMESSAGE;

-		vcrSendMessage.session = (long)sock;

-		vcrSendMessage.r = r;

-		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);

-	}

-	

-	return r;

-}

-

-

-/*

-==================

-NET_CanSendMessage

-

-Returns true or false if the given qsocket can currently accept a

-message to be transmitted.

-==================

-*/

-qboolean NET_CanSendMessage (qsocket_t *sock)

-{

-	int		r;

-	

-	if (!sock)

-		return false;

-

-	if (sock->disconnected)

-		return false;

-

-	SetNetTime();

-

-	r = sfunc.CanSendMessage(sock);

-	

-	if (recording)

-	{

-		vcrSendMessage.time = host_time;

-		vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;

-		vcrSendMessage.session = (long)sock;

-		vcrSendMessage.r = r;

-		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);

-	}

-	

-	return r;

-}

-

-

-int NET_SendToAll(sizebuf_t *data, int blocktime)

-{

-	double		start;

-	int			i;

-	int			count = 0;

-	qboolean	state1 [MAX_SCOREBOARD];

-	qboolean	state2 [MAX_SCOREBOARD];

-

-	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)

-	{

-		if (!host_client->netconnection)

-			continue;

-		if (host_client->active)

-		{

-			if (host_client->netconnection->driver == 0)

-			{

-				NET_SendMessage(host_client->netconnection, data);

-				state1[i] = true;

-				state2[i] = true;

-				continue;

-			}

-			count++;

-			state1[i] = false;

-			state2[i] = false;

-		}

-		else

-		{

-			state1[i] = true;

-			state2[i] = true;

-		}

-	}

-

-	start = Sys_FloatTime();

-	while (count)

-	{

-		count = 0;

-		for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)

-		{

-			if (! state1[i])

-			{

-				if (NET_CanSendMessage (host_client->netconnection))

-				{

-					state1[i] = true;

-					NET_SendMessage(host_client->netconnection, data);

-				}

-				else

-				{

-					NET_GetMessage (host_client->netconnection);

-				}

-				count++;

-				continue;

-			}

-

-			if (! state2[i])

-			{

-				if (NET_CanSendMessage (host_client->netconnection))

-				{

-					state2[i] = true;

-				}

-				else

-				{

-					NET_GetMessage (host_client->netconnection);

-				}

-				count++;

-				continue;

-			}

-		}

-		if ((Sys_FloatTime() - start) > blocktime)

-			break;

-	}

-	return count;

-}

-

-

-//=============================================================================

-

-/*

-====================

-NET_Init

-====================

-*/

-

-void NET_Init (void)

-{

-	int			i;

-	int			controlSocket;

-	qsocket_t	*s;

-

-	if (COM_CheckParm("-playback"))

-	{

-		net_numdrivers = 1;

-		net_drivers[0].Init = VCR_Init;

-	}

-

-	if (COM_CheckParm("-record"))

-		recording = true;

-

-	i = COM_CheckParm ("-port");

-	if (!i)

-		i = COM_CheckParm ("-udpport");

-	if (!i)

-		i = COM_CheckParm ("-ipxport");

-

-	if (i)

-	{

-		if (i < com_argc-1)

-			DEFAULTnet_hostport = Q_atoi (com_argv[i+1]);

-		else

-			Sys_Error ("NET_Init: you must specify a number after -port");

-	}

-	net_hostport = DEFAULTnet_hostport;

-

-	if (COM_CheckParm("-listen") || cls.state == ca_dedicated)

-		listening = true;

-	net_numsockets = svs.maxclientslimit;

-	if (cls.state != ca_dedicated)

-		net_numsockets++;

-

-	SetNetTime();

-

-	for (i = 0; i < net_numsockets; i++)

-	{

-		s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");

-		s->next = net_freeSockets;

-		net_freeSockets = s;

-		s->disconnected = true;

-	}

-

-	// allocate space for network message buffer

-	SZ_Alloc (&net_message, NET_MAXMESSAGE);

-

-	Cvar_RegisterVariable (&net_messagetimeout);

-	Cvar_RegisterVariable (&hostname);

-	Cvar_RegisterVariable (&config_com_port);

-	Cvar_RegisterVariable (&config_com_irq);

-	Cvar_RegisterVariable (&config_com_baud);

-	Cvar_RegisterVariable (&config_com_modem);

-	Cvar_RegisterVariable (&config_modem_dialtype);

-	Cvar_RegisterVariable (&config_modem_clear);

-	Cvar_RegisterVariable (&config_modem_init);

-	Cvar_RegisterVariable (&config_modem_hangup);

-#ifdef IDGODS

-	Cvar_RegisterVariable (&idgods);

-#endif

-

-	Cmd_AddCommand ("slist", NET_Slist_f);

-	Cmd_AddCommand ("listen", NET_Listen_f);

-	Cmd_AddCommand ("maxplayers", MaxPlayers_f);

-	Cmd_AddCommand ("port", NET_Port_f);

-

-	// initialize all the drivers

-	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)

-		{

-		controlSocket = net_drivers[net_driverlevel].Init();

-		if (controlSocket == -1)

-			continue;

-		net_drivers[net_driverlevel].initialized = true;

-		net_drivers[net_driverlevel].controlSock = controlSocket;

-		if (listening)

-			net_drivers[net_driverlevel].Listen (true);

-		}

-

-	if (*my_ipx_address)

-		Con_DPrintf("IPX address %s\n", my_ipx_address);

-	if (*my_tcpip_address)

-		Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);

-}

-

-/*

-====================

-NET_Shutdown

-====================

-*/

-

-void		NET_Shutdown (void)

-{

-	qsocket_t	*sock;

-

-	SetNetTime();

-

-	for (sock = net_activeSockets; sock; sock = sock->next)

-		NET_Close(sock);

-

-//

-// shutdown the drivers

-//

-	for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)

-	{

-		if (net_drivers[net_driverlevel].initialized == true)

-		{

-			net_drivers[net_driverlevel].Shutdown ();

-			net_drivers[net_driverlevel].initialized = false;

-		}

-	}

-

-	if (vcrFile != -1)

-	{

-		Con_Printf ("Closing vcrfile.\n");

-		Sys_FileClose(vcrFile);

-	}

-}

-

-

-static PollProcedure *pollProcedureList = NULL;

-

-void NET_Poll(void)

-{

-	PollProcedure *pp;

-	qboolean	useModem;

-

-	if (!configRestored)

-	{

-		if (serialAvailable)

-		{

-			if (config_com_modem.value == 1.0)

-				useModem = true;

-			else

-				useModem = false;

-			SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);

-			SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);

-		}

-		configRestored = true;

-	}

-

-	SetNetTime();

-

-	for (pp = pollProcedureList; pp; pp = pp->next)

-	{

-		if (pp->nextTime > net_time)

-			break;

-		pollProcedureList = pp->next;

-		pp->procedure(pp->arg);

-	}

-}

-

-

-void SchedulePollProcedure(PollProcedure *proc, double timeOffset)

-{

-	PollProcedure *pp, *prev;

-

-	proc->nextTime = Sys_FloatTime() + timeOffset;

-	for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)

-	{

-		if (pp->nextTime >= proc->nextTime)

-			break;

-		prev = pp;

-	}

-

-	if (prev == NULL)

-	{

-		proc->next = pollProcedureList;

-		pollProcedureList = proc;

-		return;

-	}

-

-	proc->next = pp;

-	prev->next = proc;

-}

-

-

-#ifdef IDGODS

-#define IDNET	0xc0f62800

-

-qboolean IsID(struct qsockaddr *addr)

-{

-	if (idgods.value == 0.0)

-		return false;

-

-	if (addr->sa_family != 2)

-		return false;

-

-	if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)

-		return true;

-	return false;

-}

-#endif

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_main.c
+
+#include "quakedef.h"
+#include "net_vcr.h"
+
+qsocket_t	*net_activeSockets = NULL;
+qsocket_t	*net_freeSockets = NULL;
+int			net_numsockets = 0;
+
+qboolean	serialAvailable = false;
+qboolean	ipxAvailable = false;
+qboolean	tcpipAvailable = false;
+
+int			net_hostport;
+int			DEFAULTnet_hostport = 26000;
+
+char		my_ipx_address[NET_NAMELEN];
+char		my_tcpip_address[NET_NAMELEN];
+
+void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
+void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
+void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
+void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
+
+static qboolean	listening = false;
+
+qboolean	slistInProgress = false;
+qboolean	slistSilent = false;
+qboolean	slistLocal = true;
+static double	slistStartTime;
+static int		slistLastShown;
+
+static void Slist_Send(void*);
+static void Slist_Poll(void*);
+PollProcedure	slistSendProcedure = {NULL, 0.0, Slist_Send, NULL};
+PollProcedure	slistPollProcedure = {NULL, 0.0, Slist_Poll, NULL};
+
+
+sizebuf_t		net_message;
+int				net_activeconnections = 0;
+
+int messagesSent = 0;
+int messagesReceived = 0;
+int unreliableMessagesSent = 0;
+int unreliableMessagesReceived = 0;
+
+cvar_t	net_messagetimeout = CVAR2("net_messagetimeout","300");
+cvar_t	hostname = CVAR2("hostname", "UNNAMED");
+
+qboolean	configRestored = false;
+cvar_t	config_com_port = CVAR3("_config_com_port", "0x3f8", true);
+cvar_t	config_com_irq = CVAR3("_config_com_irq", "4", true);
+cvar_t	config_com_baud = CVAR3("_config_com_baud", "57600", true);
+cvar_t	config_com_modem = CVAR3("_config_com_modem", "1", true);
+cvar_t	config_modem_dialtype = CVAR3("_config_modem_dialtype", "T", true);
+cvar_t	config_modem_clear = CVAR3("_config_modem_clear", "ATZ", true);
+cvar_t	config_modem_init = CVAR3("_config_modem_init", "", true);
+cvar_t	config_modem_hangup = CVAR3("_config_modem_hangup", "AT H", true);
+
+#ifdef IDGODS
+cvar_t	idgods = CVAR2("idgods", "0");
+#endif
+
+int	vcrFile = -1;
+qboolean recording = false;
+
+// these two macros are to make the code more readable
+#define sfunc	net_drivers[sock->driver]
+#define dfunc	net_drivers[net_driverlevel]
+
+int	net_driverlevel;
+
+
+double			net_time;
+
+double SetNetTime(void)
+{
+	net_time = Sys_FloatTime();
+	return net_time;
+}
+
+
+/*
+===================
+NET_NewQSocket
+
+Called by drivers when a new communications endpoint is required
+The sequence and buffer fields will be filled in properly
+===================
+*/
+qsocket_t *NET_NewQSocket (void)
+{
+	qsocket_t	*sock;
+
+	if (net_freeSockets == NULL)
+		return NULL;
+
+	if (net_activeconnections >= svs.maxclients)
+		return NULL;
+
+	// get one from free list
+	sock = net_freeSockets;
+	net_freeSockets = sock->next;
+
+	// add it to active list
+	sock->next = net_activeSockets;
+	net_activeSockets = sock;
+
+	sock->disconnected = false;
+	sock->connecttime = net_time;
+	Q_strcpy (sock->address,"UNSET ADDRESS");
+	sock->driver = net_driverlevel;
+	sock->socket = 0;
+	sock->driverdata = NULL;
+	sock->canSend = true;
+	sock->sendNext = false;
+	sock->lastMessageTime = net_time;
+	sock->ackSequence = 0;
+	sock->sendSequence = 0;
+	sock->unreliableSendSequence = 0;
+	sock->sendMessageLength = 0;
+	sock->receiveSequence = 0;
+	sock->unreliableReceiveSequence = 0;
+	sock->receiveMessageLength = 0;
+
+	return sock;
+}
+
+
+void NET_FreeQSocket(qsocket_t *sock)
+{
+	qsocket_t	*s;
+
+	// remove it from active list
+	if (sock == net_activeSockets)
+		net_activeSockets = net_activeSockets->next;
+	else
+	{
+		for (s = net_activeSockets; s; s = s->next)
+			if (s->next == sock)
+			{
+				s->next = sock->next;
+				break;
+			}
+		if (!s)
+			Sys_Error ("NET_FreeQSocket: not active\n");
+	}
+
+	// add it to free list
+	sock->next = net_freeSockets;
+	net_freeSockets = sock;
+	sock->disconnected = true;
+}
+
+
+static void NET_Listen_f (void)
+{
+	if (Cmd_Argc () != 2)
+	{
+		Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
+		return;
+	}
+
+	listening = Q_atoi(Cmd_Argv(1)) ? true : false;
+
+	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
+	{
+		if (net_drivers[net_driverlevel].initialized == false)
+			continue;
+		dfunc.Listen (listening);
+	}
+}
+
+
+static void MaxPlayers_f (void)
+{
+	int 	n;
+
+	if (Cmd_Argc () != 2)
+	{
+		Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
+		return;
+	}
+
+	if (sv.active)
+	{
+		Con_Printf ("maxplayers can not be changed while a server is running.\n");
+		return;
+	}
+
+	n = Q_atoi(Cmd_Argv(1));
+	if (n < 1)
+		n = 1;
+	if (n > svs.maxclientslimit)
+	{
+		n = svs.maxclientslimit;
+		Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
+	}
+
+	if ((n == 1) && listening)
+		Cbuf_AddText ("listen 0\n");
+
+	if ((n > 1) && (!listening))
+		Cbuf_AddText ("listen 1\n");
+
+	svs.maxclients = n;
+	if (n == 1)
+		Cvar_Set ("deathmatch", "0");
+	else
+		Cvar_Set ("deathmatch", "1");
+}
+
+
+static void NET_Port_f (void)
+{
+	int 	n;
+
+	if (Cmd_Argc () != 2)
+	{
+		Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
+		return;
+	}
+
+	n = Q_atoi(Cmd_Argv(1));
+	if (n < 1 || n > 65534)
+	{
+		Con_Printf ("Bad value, must be between 1 and 65534\n");
+		return;
+	}
+
+	DEFAULTnet_hostport = n;
+	net_hostport = n;
+
+	if (listening)
+	{
+		// force a change to the new port
+		Cbuf_AddText ("listen 0\n");
+		Cbuf_AddText ("listen 1\n");
+	}
+}
+
+
+static void PrintSlistHeader(void)
+{
+	Con_Printf("Server          Map             Users\n");
+	Con_Printf("--------------- --------------- -----\n");
+	slistLastShown = 0;
+}
+
+
+static void PrintSlist(void)
+{
+	int n;
+
+	for (n = slistLastShown; n < hostCacheCount; n++)
+	{
+		if (hostcache[n].maxusers)
+			Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
+		else
+			Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
+	}
+	slistLastShown = n;
+}
+
+
+static void PrintSlistTrailer(void)
+{
+	if (hostCacheCount)
+		Con_Printf("== end list ==\n\n");
+	else
+		Con_Printf("No Quake servers found.\n\n");
+}
+
+
+void NET_Slist_f (void)
+{
+	if (slistInProgress)
+		return;
+
+	if (! slistSilent)
+	{
+		Con_Printf("Looking for Quake servers...\n");
+		PrintSlistHeader();
+	}
+
+	slistInProgress = true;
+	slistStartTime = Sys_FloatTime();
+
+	SchedulePollProcedure(&slistSendProcedure, 0.0);
+	SchedulePollProcedure(&slistPollProcedure, 0.1);
+
+	hostCacheCount = 0;
+}
+
+
+static void Slist_Send(void* /* arg */)
+{
+	for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
+	{
+		if (!slistLocal && net_driverlevel == 0)
+			continue;
+		if (net_drivers[net_driverlevel].initialized == false)
+			continue;
+		dfunc.SearchForHosts (true);
+	}
+
+	if ((Sys_FloatTime() - slistStartTime) < 0.5)
+		SchedulePollProcedure(&slistSendProcedure, 0.75);
+}
+
+
+static void Slist_Poll(void* /* arg */)
+{
+	for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
+	{
+		if (!slistLocal && net_driverlevel == 0)
+			continue;
+		if (net_drivers[net_driverlevel].initialized == false)
+			continue;
+		dfunc.SearchForHosts (false);
+	}
+
+	if (! slistSilent)
+		PrintSlist();
+
+	if ((Sys_FloatTime() - slistStartTime) < 1.5)
+	{
+		SchedulePollProcedure(&slistPollProcedure, 0.1);
+		return;
+	}
+
+	if (! slistSilent)
+		PrintSlistTrailer();
+	slistInProgress = false;
+	slistSilent = false;
+	slistLocal = true;
+}
+
+
+/*
+===================
+NET_Connect
+===================
+*/
+
+int hostCacheCount = 0;
+hostcache_t hostcache[HOSTCACHESIZE];
+
+qsocket_t *NET_Connect (const char *host)
+{
+	qsocket_t		*ret;
+	int				n;
+	int				numdrivers = net_numdrivers;
+
+	SetNetTime();
+
+	if (host && *host == 0)
+		host = NULL;
+
+	if (host)
+	{
+		if (Q_strcasecmp (host, "local") == 0)
+		{
+			numdrivers = 1;
+			goto JustDoIt;
+		}
+
+		if (hostCacheCount)
+		{
+			for (n = 0; n < hostCacheCount; n++)
+				if (Q_strcasecmp (host, hostcache[n].name) == 0)
+				{
+					host = hostcache[n].cname;
+					break;
+				}
+			if (n < hostCacheCount)
+				goto JustDoIt;
+		}
+	}
+
+	slistSilent = host ? true : false;
+	NET_Slist_f ();
+
+	while(slistInProgress)
+		NET_Poll();
+
+	if (host == NULL)
+	{
+		if (hostCacheCount != 1)
+			return NULL;
+		host = hostcache[0].cname;
+		Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
+	}
+
+	if (hostCacheCount)
+		for (n = 0; n < hostCacheCount; n++)
+			if (Q_strcasecmp (host, hostcache[n].name) == 0)
+			{
+				host = hostcache[n].cname;
+				break;
+			}
+
+JustDoIt:
+	for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
+	{
+		if (net_drivers[net_driverlevel].initialized == false)
+			continue;
+		ret = dfunc.Connect (host);
+		if (ret)
+			return ret;
+	}
+
+	if (host)
+	{
+		Con_Printf("\n");
+		PrintSlistHeader();
+		PrintSlist();
+		PrintSlistTrailer();
+	}
+	
+	return NULL;
+}
+
+
+/*
+===================
+NET_CheckNewConnections
+===================
+*/
+
+struct vcrConnect_t
+{
+	double	time;
+	int		op;
+	long	session;
+} vcrConnect;
+
+qsocket_t *NET_CheckNewConnections (void)
+{
+	qsocket_t	*ret;
+
+	SetNetTime();
+
+	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
+	{
+		if (net_drivers[net_driverlevel].initialized == false)
+			continue;
+		if (net_driverlevel && listening == false)
+			continue;
+		ret = dfunc.CheckNewConnections ();
+		if (ret)
+		{
+			if (recording)
+			{
+				vcrConnect.time = host_time;
+				vcrConnect.op = VCR_OP_CONNECT;
+				vcrConnect.session = (long)ret;
+				Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
+				Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
+			}
+			return ret;
+		}
+	}
+	
+	if (recording)
+	{
+		vcrConnect.time = host_time;
+		vcrConnect.op = VCR_OP_CONNECT;
+		vcrConnect.session = 0;
+		Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
+	}
+
+	return NULL;
+}
+
+/*
+===================
+NET_Close
+===================
+*/
+void NET_Close (qsocket_t *sock)
+{
+	if (!sock)
+		return;
+
+	if (sock->disconnected)
+		return;
+
+	SetNetTime();
+
+	// call the driver_Close function
+	sfunc.Close (sock);
+
+	NET_FreeQSocket(sock);
+}
+
+
+/*
+=================
+NET_GetMessage
+
+If there is a complete message, return it in net_message
+
+returns 0 if no data is waiting
+returns 1 if a message was received
+returns -1 if connection is invalid
+=================
+*/
+
+struct vcrGetMessage_t
+{
+	double	time;
+	int		op;
+	long	session;
+	int		ret;
+	int		len;
+} vcrGetMessage;
+
+extern void PrintStats(qsocket_t *s);
+
+int	NET_GetMessage (qsocket_t *sock)
+{
+	int ret;
+
+	if (!sock)
+		return -1;
+
+	if (sock->disconnected)
+	{
+		Con_Printf("NET_GetMessage: disconnected socket\n");
+		return -1;
+	}
+
+	SetNetTime();
+
+	ret = sfunc.QGetMessage(sock);
+
+	// see if this connection has timed out
+	if (ret == 0 && sock->driver)
+	{
+		if (net_time - sock->lastMessageTime > net_messagetimeout.value)
+		{
+			NET_Close(sock);
+			return -1;
+		}
+	}
+
+
+	if (ret > 0)
+	{
+		if (sock->driver)
+		{
+			sock->lastMessageTime = net_time;
+			if (ret == 1)
+				messagesReceived++;
+			else if (ret == 2)
+				unreliableMessagesReceived++;
+		}
+
+		if (recording)
+		{
+			vcrGetMessage.time = host_time;
+			vcrGetMessage.op = VCR_OP_GETMESSAGE;
+			vcrGetMessage.session = (long)sock;
+			vcrGetMessage.ret = ret;
+			vcrGetMessage.len = net_message.cursize;
+			Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
+			Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
+		}
+	}
+	else
+	{
+		if (recording)
+		{
+			vcrGetMessage.time = host_time;
+			vcrGetMessage.op = VCR_OP_GETMESSAGE;
+			vcrGetMessage.session = (long)sock;
+			vcrGetMessage.ret = ret;
+			Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
+		}
+	}
+
+	return ret;
+}
+
+
+/*
+==================
+NET_SendMessage
+
+Try to send a complete length+message unit over the reliable stream.
+returns 0 if the message cannot be delivered reliably, but the connection
+		is still considered valid
+returns 1 if the message was sent properly
+returns -1 if the connection died
+==================
+*/
+struct vcrSendMessage_t
+{
+	double	time;
+	int		op;
+	long	session;
+	int		r;
+} vcrSendMessage;
+
+int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
+{
+	int		r;
+	
+	if (!sock)
+		return -1;
+
+	if (sock->disconnected)
+	{
+		Con_Printf("NET_SendMessage: disconnected socket\n");
+		return -1;
+	}
+
+	SetNetTime();
+	r = sfunc.QSendMessage(sock, data);
+	if (r == 1 && sock->driver)
+		messagesSent++;
+
+	if (recording)
+	{
+		vcrSendMessage.time = host_time;
+		vcrSendMessage.op = VCR_OP_SENDMESSAGE;
+		vcrSendMessage.session = (long)sock;
+		vcrSendMessage.r = r;
+		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
+	}
+	
+	return r;
+}
+
+
+int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
+{
+	int		r;
+	
+	if (!sock)
+		return -1;
+
+	if (sock->disconnected)
+	{
+		Con_Printf("NET_SendMessage: disconnected socket\n");
+		return -1;
+	}
+
+	SetNetTime();
+	r = sfunc.SendUnreliableMessage(sock, data);
+	if (r == 1 && sock->driver)
+		unreliableMessagesSent++;
+
+	if (recording)
+	{
+		vcrSendMessage.time = host_time;
+		vcrSendMessage.op = VCR_OP_SENDMESSAGE;
+		vcrSendMessage.session = (long)sock;
+		vcrSendMessage.r = r;
+		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
+	}
+	
+	return r;
+}
+
+
+/*
+==================
+NET_CanSendMessage
+
+Returns true or false if the given qsocket can currently accept a
+message to be transmitted.
+==================
+*/
+qboolean NET_CanSendMessage (qsocket_t *sock)
+{
+	int		r;
+	
+	if (!sock)
+		return false;
+
+	if (sock->disconnected)
+		return false;
+
+	SetNetTime();
+
+	r = sfunc.CanSendMessage(sock);
+	
+	if (recording)
+	{
+		vcrSendMessage.time = host_time;
+		vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
+		vcrSendMessage.session = (long)sock;
+		vcrSendMessage.r = r;
+		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
+	}
+	
+	return r;
+}
+
+
+int NET_SendToAll(sizebuf_t *data, int blocktime)
+{
+	double		start;
+	int			i;
+	int			count = 0;
+	qboolean	state1 [MAX_SCOREBOARD];
+	qboolean	state2 [MAX_SCOREBOARD];
+
+	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
+	{
+		if (!host_client->netconnection)
+			continue;
+		if (host_client->active)
+		{
+			if (host_client->netconnection->driver == 0)
+			{
+				NET_SendMessage(host_client->netconnection, data);
+				state1[i] = true;
+				state2[i] = true;
+				continue;
+			}
+			count++;
+			state1[i] = false;
+			state2[i] = false;
+		}
+		else
+		{
+			state1[i] = true;
+			state2[i] = true;
+		}
+	}
+
+	start = Sys_FloatTime();
+	while (count)
+	{
+		count = 0;
+		for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
+		{
+			if (! state1[i])
+			{
+				if (NET_CanSendMessage (host_client->netconnection))
+				{
+					state1[i] = true;
+					NET_SendMessage(host_client->netconnection, data);
+				}
+				else
+				{
+					NET_GetMessage (host_client->netconnection);
+				}
+				count++;
+				continue;
+			}
+
+			if (! state2[i])
+			{
+				if (NET_CanSendMessage (host_client->netconnection))
+				{
+					state2[i] = true;
+				}
+				else
+				{
+					NET_GetMessage (host_client->netconnection);
+				}
+				count++;
+				continue;
+			}
+		}
+		if ((Sys_FloatTime() - start) > blocktime)
+			break;
+	}
+	return count;
+}
+
+
+//=============================================================================
+
+/*
+====================
+NET_Init
+====================
+*/
+
+void NET_Init (void)
+{
+	int			i;
+	int			controlSocket;
+	qsocket_t	*s;
+
+	if (COM_CheckParm("-playback"))
+	{
+		net_numdrivers = 1;
+		net_drivers[0].Init = VCR_Init;
+	}
+
+	if (COM_CheckParm("-record"))
+		recording = true;
+
+	i = COM_CheckParm ("-port");
+	if (!i)
+		i = COM_CheckParm ("-udpport");
+	if (!i)
+		i = COM_CheckParm ("-ipxport");
+
+	if (i)
+	{
+		if (i < com_argc-1)
+			DEFAULTnet_hostport = Q_atoi (com_argv[i+1]);
+		else
+			Sys_Error ("NET_Init: you must specify a number after -port");
+	}
+	net_hostport = DEFAULTnet_hostport;
+
+	if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
+		listening = true;
+	net_numsockets = svs.maxclientslimit;
+	if (cls.state != ca_dedicated)
+		net_numsockets++;
+
+	SetNetTime();
+
+	for (i = 0; i < net_numsockets; i++)
+	{
+		s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
+		s->next = net_freeSockets;
+		net_freeSockets = s;
+		s->disconnected = true;
+	}
+
+	// allocate space for network message buffer
+	SZ_Alloc (&net_message, NET_MAXMESSAGE);
+
+	Cvar_RegisterVariable (&net_messagetimeout);
+	Cvar_RegisterVariable (&hostname);
+	Cvar_RegisterVariable (&config_com_port);
+	Cvar_RegisterVariable (&config_com_irq);
+	Cvar_RegisterVariable (&config_com_baud);
+	Cvar_RegisterVariable (&config_com_modem);
+	Cvar_RegisterVariable (&config_modem_dialtype);
+	Cvar_RegisterVariable (&config_modem_clear);
+	Cvar_RegisterVariable (&config_modem_init);
+	Cvar_RegisterVariable (&config_modem_hangup);
+#ifdef IDGODS
+	Cvar_RegisterVariable (&idgods);
+#endif
+
+	Cmd_AddCommand ("slist", NET_Slist_f);
+	Cmd_AddCommand ("listen", NET_Listen_f);
+	Cmd_AddCommand ("maxplayers", MaxPlayers_f);
+	Cmd_AddCommand ("port", NET_Port_f);
+
+	// initialize all the drivers
+	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
+		{
+		controlSocket = net_drivers[net_driverlevel].Init();
+		if (controlSocket == -1)
+			continue;
+		net_drivers[net_driverlevel].initialized = true;
+		net_drivers[net_driverlevel].controlSock = controlSocket;
+		if (listening)
+			net_drivers[net_driverlevel].Listen (true);
+		}
+
+	if (*my_ipx_address)
+		Con_DPrintf("IPX address %s\n", my_ipx_address);
+	if (*my_tcpip_address)
+		Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
+}
+
+/*
+====================
+NET_Shutdown
+====================
+*/
+
+void		NET_Shutdown (void)
+{
+	qsocket_t	*sock;
+
+	SetNetTime();
+
+	for (sock = net_activeSockets; sock; sock = sock->next)
+		NET_Close(sock);
+
+//
+// shutdown the drivers
+//
+	for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
+	{
+		if (net_drivers[net_driverlevel].initialized == true)
+		{
+			net_drivers[net_driverlevel].Shutdown ();
+			net_drivers[net_driverlevel].initialized = false;
+		}
+	}
+
+	if (vcrFile != -1)
+	{
+		Con_Printf ("Closing vcrfile.\n");
+		Sys_FileClose(vcrFile);
+	}
+}
+
+
+static PollProcedure *pollProcedureList = NULL;
+
+void NET_Poll(void)
+{
+	PollProcedure *pp;
+	qboolean	useModem;
+
+	if (!configRestored)
+	{
+		if (serialAvailable)
+		{
+			if (config_com_modem.value == 1.0)
+				useModem = true;
+			else
+				useModem = false;
+			SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
+			SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
+		}
+		configRestored = true;
+	}
+
+	SetNetTime();
+
+	for (pp = pollProcedureList; pp; pp = pp->next)
+	{
+		if (pp->nextTime > net_time)
+			break;
+		pollProcedureList = pp->next;
+		pp->procedure(pp->arg);
+	}
+}
+
+
+void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
+{
+	PollProcedure *pp, *prev;
+
+	proc->nextTime = Sys_FloatTime() + timeOffset;
+	for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
+	{
+		if (pp->nextTime >= proc->nextTime)
+			break;
+		prev = pp;
+	}
+
+	if (prev == NULL)
+	{
+		proc->next = pollProcedureList;
+		pollProcedureList = proc;
+		return;
+	}
+
+	proc->next = pp;
+	prev->next = proc;
+}
+
+
+#ifdef IDGODS
+#define IDNET	0xc0f62800
+
+qboolean IsID(struct qsockaddr *addr)
+{
+	if (idgods.value == 0.0)
+		return false;
+
+	if (addr->sa_family != 2)
+		return false;
+
+	if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
+		return true;
+	return false;
+}
+#endif
diff --git a/quake/src/WinQuake/net_mp.c b/quake/src/WinQuake/net_mp.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_mp.c
rename to quake/src/WinQuake/net_mp.cpp
diff --git a/quake/src/WinQuake/net_none.c b/quake/src/WinQuake/net_none.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_none.c
rename to quake/src/WinQuake/net_none.cpp
diff --git a/quake/src/WinQuake/net_ser.c b/quake/src/WinQuake/net_ser.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_ser.c
rename to quake/src/WinQuake/net_ser.cpp
diff --git a/quake/src/WinQuake/net_udp.c b/quake/src/WinQuake/net_udp.cpp
old mode 100644
new mode 100755
similarity index 74%
rename from quake/src/WinQuake/net_udp.c
rename to quake/src/WinQuake/net_udp.cpp
index f23e4ef..68fba41
--- a/quake/src/WinQuake/net_udp.c
+++ b/quake/src/WinQuake/net_udp.cpp
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // net_udp.c
 
 #include "quakedef.h"
@@ -28,6 +28,9 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
 
 #ifdef __sun__
 #include <sys/filio.h>
@@ -37,9 +40,6 @@
 #include <libc.h>
 #endif
 
-extern int gethostname (char *, int);
-extern int close (int);
-
 extern cvar_t hostname;
 
 static int net_acceptsocket = -1;		// socket for fielding new connections
@@ -51,6 +51,89 @@
 
 #include "net_udp.h"
 
+// **** Start of Android-specific code ****
+// copied from ifc_utils.c
+//
+// This isn't a good long-term solution:
+// 1) It is hard-wired to a particular wireless driver
+// 2) It doesn't handle the IP address changing over time
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+static int ifc_ctl_sock = -1;
+
+int ifc_init(void)
+{
+    if (ifc_ctl_sock == -1) {
+        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
+        if (ifc_ctl_sock < 0) {
+        	Con_Printf("socket() failed: %s\n", strerror(errno));
+        }
+    }
+    return ifc_ctl_sock < 0 ? -1 : 0;
+}
+
+void ifc_close(void)
+{
+    if (ifc_ctl_sock != -1) {
+        (void)close(ifc_ctl_sock);
+        ifc_ctl_sock = -1;
+    }
+}
+
+static void ifc_init_ifr(const char *name, struct ifreq *ifr)
+{
+    memset(ifr, 0, sizeof(struct ifreq));
+    strncpy(ifr->ifr_name, name, IFNAMSIZ);
+    ifr->ifr_name[IFNAMSIZ - 1] = 0;
+}
+
+int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
+{
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    if (addr != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
+            *addr = 0;
+        } else {
+            *addr = ((struct sockaddr_in*) (void*) &ifr.ifr_addr)->sin_addr.s_addr;
+        }
+    }
+
+    if (mask != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
+            *mask = 0;
+        } else {
+            *mask = ((struct sockaddr_in*) (void*) &ifr.ifr_addr)->sin_addr.s_addr;
+        }
+    }
+
+    if (flags != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
+            *flags = 0;
+        } else {
+            *flags = ifr.ifr_flags;
+        }
+    }
+
+    return 0;
+}
+
+void AndroidGetAddr() {
+	if (ifc_init()) {
+		return;
+	}
+	in_addr_t addr;
+	ifc_get_info("tiwlan0", &addr, 0, 0);
+	myAddr = addr;
+	ifc_close();
+}
+
+
+// **** End of Android-specific code ****
+
 //=============================================================================
 
 int UDP_Init (void)
@@ -59,13 +142,23 @@
 	char	buff[MAXHOSTNAMELEN];
 	struct qsockaddr addr;
 	char *colon;
-	
+
 	if (COM_CheckParm ("-noudp"))
 		return -1;
 
+#if 1 // Android
+	AndroidGetAddr();
+#else
 	// determine my name & address
 	gethostname(buff, MAXHOSTNAMELEN);
 	local = gethostbyname(buff);
+
+	if(!local)
+	{
+		Con_Printf("Could not gethostbyname(\"%s\")\n", buff);
+		return -1;
+	}
+
 	myAddr = *(int *)local->h_addr_list[0];
 
 	// if the quake hostname isn't set, set it to the machine name
@@ -74,13 +167,19 @@
 		buff[15] = 0;
 		Cvar_Set ("hostname", buff);
 	}
-
+#endif
 	if ((net_controlsocket = UDP_OpenSocket (0)) == -1)
 		Sys_Error("UDP_Init: Unable to open control socket\n");
 
-	((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
-	((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
-	((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport);
+	sockaddr_in temp;
+
+	memcpy(&temp, &broadcastaddr, sizeof(temp));
+
+	temp.sin_family = AF_INET;
+	temp.sin_addr.s_addr = INADDR_BROADCAST;
+	temp.sin_port = htons(net_hostport);
+
+	memcpy(&broadcastaddr, &temp, sizeof(temp));
 
 	UDP_GetSocketAddr (net_controlsocket, &addr);
 	Q_strcpy(my_tcpip_address,  UDP_AddrToString (&addr));
@@ -128,7 +227,10 @@
 int UDP_OpenSocket (int port)
 {
 	int newsocket;
-	struct sockaddr_in address;
+	union {
+	    struct sockaddr_in in;
+	    struct sockaddr sockaddr;
+	} address;
 	qboolean _true = true;
 
 	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
@@ -137,10 +239,10 @@
 	if (ioctl (newsocket, FIONBIO, (char *)&_true) == -1)
 		goto ErrorReturn;
 
-	address.sin_family = AF_INET;
-	address.sin_addr.s_addr = INADDR_ANY;
-	address.sin_port = htons(port);
-	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
+	address.in.sin_family = AF_INET;
+	address.in.sin_addr.s_addr = INADDR_ANY;
+	address.in.sin_port = htons(port);
+	if( bind (newsocket, &address.sockaddr, sizeof(address.in)) == -1)
 		goto ErrorReturn;
 
 	return newsocket;
@@ -169,7 +271,7 @@
 the local network components to fill in the rest
 ============
 */
-static int PartialIPAddress (char *in, struct qsockaddr *hostaddr)
+static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr)
 {
 	char buff[256];
 	char *b;
@@ -178,7 +280,7 @@
 	int mask;
 	int run;
 	int port;
-	
+
 	buff[0] = '.';
 	b = buff;
 	strcpy(buff+1, in);
@@ -205,16 +307,16 @@
 		mask<<=8;
 		addr = (addr<<8) + num;
 	}
-	
+
 	if (*b++ == ':')
 		port = Q_atoi(b);
 	else
 		port = net_hostport;
 
 	hostaddr->sa_family = AF_INET;
-	((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);	
+	((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
 	((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
-	
+
 	return 0;
 }
 //=============================================================================
@@ -247,7 +349,7 @@
 	int addrlen = sizeof (struct qsockaddr);
 	int ret;
 
-	ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
+	ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, (socklen_t*) &addrlen);
 	if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
 		return 0;
 	return ret;
@@ -314,7 +416,7 @@
 
 //=============================================================================
 
-int UDP_StringToAddr (char *string, struct qsockaddr *addr)
+int UDP_StringToAddr (const char *string, struct qsockaddr *addr)
 {
 	int ha1, ha2, ha3, ha4, hp;
 	int ipaddr;
@@ -336,9 +438,9 @@
 	unsigned int a;
 
 	Q_memset(addr, 0, sizeof(struct qsockaddr));
-	getsockname(socket, (struct sockaddr *)addr, &addrlen);
+	getsockname(socket, (struct sockaddr *)addr, (socklen_t*) &addrlen);
 	a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
-	if (a == 0 || a == inet_addr("127.0.0.1"))
+	if (a == 0 || (in_addr_t) a == inet_addr("127.0.0.1"))
 		((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
 
 	return 0;
@@ -363,19 +465,19 @@
 
 //=============================================================================
 
-int UDP_GetAddrFromName(char *name, struct qsockaddr *addr)
+int UDP_GetAddrFromName(const char *name, struct qsockaddr *addr)
 {
 	struct hostent *hostentry;
 
 	if (name[0] >= '0' && name[0] <= '9')
 		return PartialIPAddress (name, addr);
-	
+
 	hostentry = gethostbyname (name);
 	if (!hostentry)
 		return -1;
 
 	addr->sa_family = AF_INET;
-	((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);	
+	((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);
 	((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
 
 	return 0;
diff --git a/quake/src/WinQuake/net_udp.h b/quake/src/WinQuake/net_udp.h
index b1cbcdb..40e30a2 100644
--- a/quake/src/WinQuake/net_udp.h
+++ b/quake/src/WinQuake/net_udp.h
@@ -1,39 +1,39 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_udp.h

-

-int  UDP_Init (void);

-void UDP_Shutdown (void);

-void UDP_Listen (qboolean state);

-int  UDP_OpenSocket (int port);

-int  UDP_CloseSocket (int socket);

-int  UDP_Connect (int socket, struct qsockaddr *addr);

-int  UDP_CheckNewConnections (void);

-int  UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr);

-int  UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr);

-int  UDP_Broadcast (int socket, byte *buf, int len);

-char *UDP_AddrToString (struct qsockaddr *addr);

-int  UDP_StringToAddr (char *string, struct qsockaddr *addr);

-int  UDP_GetSocketAddr (int socket, struct qsockaddr *addr);

-int  UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);

-int  UDP_GetAddrFromName (char *name, struct qsockaddr *addr);

-int  UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);

-int  UDP_GetSocketPort (struct qsockaddr *addr);

-int  UDP_SetSocketPort (struct qsockaddr *addr, int port);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_udp.h
+
+int  UDP_Init (void);
+void UDP_Shutdown (void);
+void UDP_Listen (qboolean state);
+int  UDP_OpenSocket (int port);
+int  UDP_CloseSocket (int socket);
+int  UDP_Connect (int socket, struct qsockaddr *addr);
+int  UDP_CheckNewConnections (void);
+int  UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
+int  UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
+int  UDP_Broadcast (int socket, byte *buf, int len);
+char *UDP_AddrToString (struct qsockaddr *addr);
+int  UDP_StringToAddr (const char *string, struct qsockaddr *addr);
+int  UDP_GetSocketAddr (int socket, struct qsockaddr *addr);
+int  UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);
+int  UDP_GetAddrFromName (const char *name, struct qsockaddr *addr);
+int  UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
+int  UDP_GetSocketPort (struct qsockaddr *addr);
+int  UDP_SetSocketPort (struct qsockaddr *addr, int port);
diff --git a/quake/src/WinQuake/net_vcr.c b/quake/src/WinQuake/net_vcr.cpp
old mode 100644
new mode 100755
similarity index 88%
rename from quake/src/WinQuake/net_vcr.c
rename to quake/src/WinQuake/net_vcr.cpp
index 2833909..6570a28
--- a/quake/src/WinQuake/net_vcr.c
+++ b/quake/src/WinQuake/net_vcr.cpp
@@ -1,167 +1,172 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_vcr.c

-

-#include "quakedef.h"

-#include "net_vcr.h"

-

-extern int vcrFile;

-

-// This is the playback portion of the VCR.  It reads the file produced

-// by the recorder and plays it back to the host.  The recording contains

-// everything necessary (events, timestamps, and data) to duplicate the game

-// from the viewpoint of everything above the network layer.

-

-static struct

-{

-	double	time;

-	int		op;

-	long	session;

-}	next;

-

-int VCR_Init (void)

-{

-	net_drivers[0].Init = VCR_Init;

-

-	net_drivers[0].SearchForHosts = VCR_SearchForHosts;

-	net_drivers[0].Connect = VCR_Connect;

-	net_drivers[0].CheckNewConnections = VCR_CheckNewConnections;

-	net_drivers[0].QGetMessage = VCR_GetMessage;

-	net_drivers[0].QSendMessage = VCR_SendMessage;

-	net_drivers[0].CanSendMessage = VCR_CanSendMessage;

-	net_drivers[0].Close = VCR_Close;

-	net_drivers[0].Shutdown = VCR_Shutdown;

-

-	Sys_FileRead(vcrFile, &next, sizeof(next));

-	return 0;

-}

-

-void VCR_ReadNext (void)

-{

-	if (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0)

-	{

-		next.op = 255;

-		Sys_Error ("=== END OF PLAYBACK===\n");

-	}

-	if (next.op < 1 || next.op > VCR_MAX_MESSAGE)

-		Sys_Error ("VCR_ReadNext: bad op");

-}

-

-

-void VCR_Listen (qboolean state)

-{

-}

-

-

-void VCR_Shutdown (void)

-{

-}

-

-

-int VCR_GetMessage (qsocket_t *sock)

-{

-	int	ret;

-	

-	if (host_time != next.time || next.op != VCR_OP_GETMESSAGE || next.session != *(long *)(&sock->driverdata))

-		Sys_Error ("VCR missmatch");

-

-	Sys_FileRead(vcrFile, &ret, sizeof(int));

-	if (ret != 1)

-	{

-		VCR_ReadNext ();

-		return ret;

-	}

-

-	Sys_FileRead(vcrFile, &net_message.cursize, sizeof(int));

-	Sys_FileRead(vcrFile, net_message.data, net_message.cursize);

-

-	VCR_ReadNext ();

-

-	return 1;

-}

-

-

-int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data)

-{

-	int	ret;

-

-	if (host_time != next.time || next.op != VCR_OP_SENDMESSAGE || next.session != *(long *)(&sock->driverdata))

-		Sys_Error ("VCR missmatch");

-

-	Sys_FileRead(vcrFile, &ret, sizeof(int));

-

-	VCR_ReadNext ();

-

-	return ret;

-}

-

-

-qboolean VCR_CanSendMessage (qsocket_t *sock)

-{

-	qboolean	ret;

-

-	if (host_time != next.time || next.op != VCR_OP_CANSENDMESSAGE || next.session != *(long *)(&sock->driverdata))

-		Sys_Error ("VCR missmatch");

-

-	Sys_FileRead(vcrFile, &ret, sizeof(int));

-

-	VCR_ReadNext ();

-

-	return ret;

-}

-

-

-void VCR_Close (qsocket_t *sock)

-{

-}

-

-

-void VCR_SearchForHosts (qboolean xmit)

-{

-}

-

-

-qsocket_t *VCR_Connect (char *host)

-{

-	return NULL;

-}

-

-

-qsocket_t *VCR_CheckNewConnections (void)

-{

-	qsocket_t	*sock;

-

-	if (host_time != next.time || next.op != VCR_OP_CONNECT)

-		Sys_Error ("VCR missmatch");

-

-	if (!next.session)

-	{

-		VCR_ReadNext ();

-		return NULL;

-	}

-

-	sock = NET_NewQSocket ();

-	*(long *)(&sock->driverdata) = next.session;

-

-	Sys_FileRead (vcrFile, sock->address, NET_NAMELEN);

-	VCR_ReadNext ();

-

-	return sock;

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_vcr.c
+
+#include "quakedef.h"
+#include "net_vcr.h"
+
+extern int vcrFile;
+
+// This is the playback portion of the VCR.  It reads the file produced
+// by the recorder and plays it back to the host.  The recording contains
+// everything necessary (events, timestamps, and data) to duplicate the game
+// from the viewpoint of everything above the network layer.
+
+static struct
+{
+	double	time;
+	int		op;
+	long	session;
+}	next;
+
+int VCR_Init (void)
+{
+	net_drivers[0].Init = VCR_Init;
+
+	net_drivers[0].SearchForHosts = VCR_SearchForHosts;
+	net_drivers[0].Connect = VCR_Connect;
+	net_drivers[0].CheckNewConnections = VCR_CheckNewConnections;
+	net_drivers[0].QGetMessage = VCR_GetMessage;
+	net_drivers[0].QSendMessage = VCR_SendMessage;
+	net_drivers[0].CanSendMessage = VCR_CanSendMessage;
+	net_drivers[0].Close = VCR_Close;
+	net_drivers[0].Shutdown = VCR_Shutdown;
+
+	Sys_FileRead(vcrFile, &next, sizeof(next));
+	return 0;
+}
+
+void VCR_ReadNext (void)
+{
+	if (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0)
+	{
+		next.op = 255;
+		Sys_Error ("=== END OF PLAYBACK===\n");
+	}
+	if (next.op < 1 || next.op > VCR_MAX_MESSAGE)
+		Sys_Error ("VCR_ReadNext: bad op");
+}
+
+
+void VCR_Listen (qboolean state)
+{
+}
+
+
+void VCR_Shutdown (void)
+{
+}
+
+static long getDriverDataAsLong(qsocket_t *sock) {
+    long driverDataAsLong;
+    memcpy(&driverDataAsLong, &sock->driverdata, sizeof(long));
+    return driverDataAsLong;
+}
+
+int VCR_GetMessage (qsocket_t *sock)
+{
+	int	ret;
+	
+	if (host_time != next.time || next.op != VCR_OP_GETMESSAGE || next.session != getDriverDataAsLong(sock))
+		Sys_Error ("VCR missmatch");
+
+	Sys_FileRead(vcrFile, &ret, sizeof(int));
+	if (ret != 1)
+	{
+		VCR_ReadNext ();
+		return ret;
+	}
+
+	Sys_FileRead(vcrFile, &net_message.cursize, sizeof(int));
+	Sys_FileRead(vcrFile, net_message.data, net_message.cursize);
+
+	VCR_ReadNext ();
+
+	return 1;
+}
+
+
+int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data)
+{
+	int	ret;
+
+	if (host_time != next.time || next.op != VCR_OP_SENDMESSAGE || next.session != getDriverDataAsLong(sock))
+		Sys_Error ("VCR missmatch");
+
+	Sys_FileRead(vcrFile, &ret, sizeof(int));
+
+	VCR_ReadNext ();
+
+	return ret;
+}
+
+
+qboolean VCR_CanSendMessage (qsocket_t *sock)
+{
+	qboolean	ret;
+
+	if (host_time != next.time || next.op != VCR_OP_CANSENDMESSAGE || next.session != getDriverDataAsLong(sock))
+		Sys_Error ("VCR missmatch");
+
+	Sys_FileRead(vcrFile, &ret, sizeof(int));
+
+	VCR_ReadNext ();
+
+	return ret;
+}
+
+
+void VCR_Close (qsocket_t *sock)
+{
+}
+
+
+void VCR_SearchForHosts (qboolean xmit)
+{
+}
+
+
+qsocket_t *VCR_Connect (const char *host)
+{
+	return NULL;
+}
+
+
+qsocket_t *VCR_CheckNewConnections (void)
+{
+	qsocket_t	*sock;
+
+	if (host_time != next.time || next.op != VCR_OP_CONNECT)
+		Sys_Error ("VCR missmatch");
+
+	if (!next.session)
+	{
+		VCR_ReadNext ();
+		return NULL;
+	}
+
+	sock = NET_NewQSocket ();
+	memcpy(&sock->driverdata, &next.session, sizeof(long));
+
+	Sys_FileRead (vcrFile, sock->address, NET_NAMELEN);
+	VCR_ReadNext ();
+
+	return sock;
+}
diff --git a/quake/src/WinQuake/net_vcr.h b/quake/src/WinQuake/net_vcr.h
index 2374697..8bb337e 100644
--- a/quake/src/WinQuake/net_vcr.h
+++ b/quake/src/WinQuake/net_vcr.h
@@ -1,37 +1,37 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// net_vcr.h

-

-#define VCR_OP_CONNECT					1

-#define VCR_OP_GETMESSAGE				2

-#define VCR_OP_SENDMESSAGE				3

-#define VCR_OP_CANSENDMESSAGE			4

-#define VCR_MAX_MESSAGE					4

-

-int			VCR_Init (void);

-void		VCR_Listen (qboolean state);

-void		VCR_SearchForHosts (qboolean xmit);

-qsocket_t 	*VCR_Connect (char *host);

-qsocket_t 	*VCR_CheckNewConnections (void);

-int			VCR_GetMessage (qsocket_t *sock);

-int			VCR_SendMessage (qsocket_t *sock, sizebuf_t *data);

-qboolean	VCR_CanSendMessage (qsocket_t *sock);

-void		VCR_Close (qsocket_t *sock);

-void		VCR_Shutdown (void);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_vcr.h
+
+#define VCR_OP_CONNECT					1
+#define VCR_OP_GETMESSAGE				2
+#define VCR_OP_SENDMESSAGE				3
+#define VCR_OP_CANSENDMESSAGE			4
+#define VCR_MAX_MESSAGE					4
+
+int			VCR_Init (void);
+void		VCR_Listen (qboolean state);
+void		VCR_SearchForHosts (qboolean xmit);
+qsocket_t 	*VCR_Connect (const char *host);
+qsocket_t 	*VCR_CheckNewConnections (void);
+int			VCR_GetMessage (qsocket_t *sock);
+int			VCR_SendMessage (qsocket_t *sock, sizebuf_t *data);
+qboolean	VCR_CanSendMessage (qsocket_t *sock);
+void		VCR_Close (qsocket_t *sock);
+void		VCR_Shutdown (void);
diff --git a/quake/src/WinQuake/net_win.c b/quake/src/WinQuake/net_win.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_win.c
rename to quake/src/WinQuake/net_win.cpp
diff --git a/quake/src/WinQuake/net_wins.c b/quake/src/WinQuake/net_wins.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_wins.c
rename to quake/src/WinQuake/net_wins.cpp
diff --git a/quake/src/WinQuake/net_wipx.c b/quake/src/WinQuake/net_wipx.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/net_wipx.c
rename to quake/src/WinQuake/net_wipx.cpp
diff --git a/quake/src/WinQuake/net_wso.c b/quake/src/WinQuake/net_wso.cpp
similarity index 100%
rename from quake/src/WinQuake/net_wso.c
rename to quake/src/WinQuake/net_wso.cpp
diff --git a/quake/src/WinQuake/nonintel.c b/quake/src/WinQuake/nonintel.cpp
old mode 100644
new mode 100755
similarity index 95%
rename from quake/src/WinQuake/nonintel.c
rename to quake/src/WinQuake/nonintel.cpp
index 66a9d10..726a18d
--- a/quake/src/WinQuake/nonintel.c
+++ b/quake/src/WinQuake/nonintel.cpp
@@ -22,8 +22,8 @@
 //

 

 #include "quakedef.h"

-#include "r_local.h"

-#include "d_local.h"

+// #include "r_local.h"

+// #include "d_local.h"

 

 #if	!id386

 

diff --git a/quake/src/WinQuake/pr_cmds.c b/quake/src/WinQuake/pr_cmds.cpp
old mode 100644
new mode 100755
similarity index 87%
rename from quake/src/WinQuake/pr_cmds.c
rename to quake/src/WinQuake/pr_cmds.cpp
index a80cd46..3dbe571
--- a/quake/src/WinQuake/pr_cmds.c
+++ b/quake/src/WinQuake/pr_cmds.cpp
@@ -1,1934 +1,1934 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-#include "quakedef.h"

-

-#define	RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))

-

-/*

-===============================================================================

-

-						BUILT-IN FUNCTIONS

-

-===============================================================================

-*/

-

-char *PF_VarString (int	first)

-{

-	int		i;

-	static char out[256];

-	

-	out[0] = 0;

-	for (i=first ; i<pr_argc ; i++)

-	{

-		strcat (out, G_STRING((OFS_PARM0+i*3)));

-	}

-	return out;

-}

-

-

-/*

-=================

-PF_errror

-

-This is a TERMINAL error, which will kill off the entire server.

-Dumps self.

-

-error(value)

-=================

-*/

-void PF_error (void)

-{

-	char	*s;

-	edict_t	*ed;

-	

-	s = PF_VarString(0);

-	Con_Printf ("======SERVER ERROR in %s:\n%s\n"

-	,pr_strings + pr_xfunction->s_name,s);

-	ed = PROG_TO_EDICT(pr_global_struct->self);

-	ED_Print (ed);

-

-	Host_Error ("Program error");

-}

-

-/*

-=================

-PF_objerror

-

-Dumps out self, then an error message.  The program is aborted and self is

-removed, but the level can continue.

-

-objerror(value)

-=================

-*/

-void PF_objerror (void)

-{

-	char	*s;

-	edict_t	*ed;

-	

-	s = PF_VarString(0);

-	Con_Printf ("======OBJECT ERROR in %s:\n%s\n"

-	,pr_strings + pr_xfunction->s_name,s);

-	ed = PROG_TO_EDICT(pr_global_struct->self);

-	ED_Print (ed);

-	ED_Free (ed);

-	

-	Host_Error ("Program error");

-}

-

-

-

-/*

-==============

-PF_makevectors

-

-Writes new values for v_forward, v_up, and v_right based on angles

-makevectors(vector)

-==============

-*/

-void PF_makevectors (void)

-{

-	AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);

-}

-

-/*

-=================

-PF_setorigin

-

-This is the only valid way to move an object without using the physics of the world (setting velocity and waiting).  Directly changing origin will not set internal links correctly, so clipping would be messed up.  This should be called when an object is spawned, and then only if it is teleported.

-

-setorigin (entity, origin)

-=================

-*/

-void PF_setorigin (void)

-{

-	edict_t	*e;

-	float	*org;

-	

-	e = G_EDICT(OFS_PARM0);

-	org = G_VECTOR(OFS_PARM1);

-	VectorCopy (org, e->v.origin);

-	SV_LinkEdict (e, false);

-}

-

-

-void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)

-{

-	float	*angles;

-	vec3_t	rmin, rmax;

-	float	bounds[2][3];

-	float	xvector[2], yvector[2];

-	float	a;

-	vec3_t	base, transformed;

-	int		i, j, k, l;

-	

-	for (i=0 ; i<3 ; i++)

-		if (min[i] > max[i])

-			PR_RunError ("backwards mins/maxs");

-

-	rotate = false;		// FIXME: implement rotation properly again

-

-	if (!rotate)

-	{

-		VectorCopy (min, rmin);

-		VectorCopy (max, rmax);

-	}

-	else

-	{

-	// find min / max for rotations

-		angles = e->v.angles;

-		

-		a = angles[1]/180 * M_PI;

-		

-		xvector[0] = cos(a);

-		xvector[1] = sin(a);

-		yvector[0] = -sin(a);

-		yvector[1] = cos(a);

-		

-		VectorCopy (min, bounds[0]);

-		VectorCopy (max, bounds[1]);

-		

-		rmin[0] = rmin[1] = rmin[2] = 9999;

-		rmax[0] = rmax[1] = rmax[2] = -9999;

-		

-		for (i=0 ; i<= 1 ; i++)

-		{

-			base[0] = bounds[i][0];

-			for (j=0 ; j<= 1 ; j++)

-			{

-				base[1] = bounds[j][1];

-				for (k=0 ; k<= 1 ; k++)

-				{

-					base[2] = bounds[k][2];

-					

-				// transform the point

-					transformed[0] = xvector[0]*base[0] + yvector[0]*base[1];

-					transformed[1] = xvector[1]*base[0] + yvector[1]*base[1];

-					transformed[2] = base[2];

-					

-					for (l=0 ; l<3 ; l++)

-					{

-						if (transformed[l] < rmin[l])

-							rmin[l] = transformed[l];

-						if (transformed[l] > rmax[l])

-							rmax[l] = transformed[l];

-					}

-				}

-			}

-		}

-	}

-	

-// set derived values

-	VectorCopy (rmin, e->v.mins);

-	VectorCopy (rmax, e->v.maxs);

-	VectorSubtract (max, min, e->v.size);

-	

-	SV_LinkEdict (e, false);

-}

-

-/*

-=================

-PF_setsize

-

-the size box is rotated by the current angle

-

-setsize (entity, minvector, maxvector)

-=================

-*/

-void PF_setsize (void)

-{

-	edict_t	*e;

-	float	*min, *max;

-	

-	e = G_EDICT(OFS_PARM0);

-	min = G_VECTOR(OFS_PARM1);

-	max = G_VECTOR(OFS_PARM2);

-	SetMinMaxSize (e, min, max, false);

-}

-

-

-/*

-=================

-PF_setmodel

-

-setmodel(entity, model)

-=================

-*/

-void PF_setmodel (void)

-{

-	edict_t	*e;

-	char	*m, **check;

-	model_t	*mod;

-	int		i;

-

-	e = G_EDICT(OFS_PARM0);

-	m = G_STRING(OFS_PARM1);

-

-// check to see if model was properly precached

-	for (i=0, check = sv.model_precache ; *check ; i++, check++)

-		if (!strcmp(*check, m))

-			break;

-			

-	if (!*check)

-		PR_RunError ("no precache: %s\n", m);

-		

-

-	e->v.model = m - pr_strings;

-	e->v.modelindex = i; //SV_ModelIndex (m);

-

-	mod = sv.models[ (int)e->v.modelindex];  // Mod_ForName (m, true);

-	

-	if (mod)

-		SetMinMaxSize (e, mod->mins, mod->maxs, true);

-	else

-		SetMinMaxSize (e, vec3_origin, vec3_origin, true);

-}

-

-/*

-=================

-PF_bprint

-

-broadcast print to everyone on server

-

-bprint(value)

-=================

-*/

-void PF_bprint (void)

-{

-	char		*s;

-

-	s = PF_VarString(0);

-	SV_BroadcastPrintf ("%s", s);

-}

-

-/*

-=================

-PF_sprint

-

-single print to a specific client

-

-sprint(clientent, value)

-=================

-*/

-void PF_sprint (void)

-{

-	char		*s;

-	client_t	*client;

-	int			entnum;

-	

-	entnum = G_EDICTNUM(OFS_PARM0);

-	s = PF_VarString(1);

-	

-	if (entnum < 1 || entnum > svs.maxclients)

-	{

-		Con_Printf ("tried to sprint to a non-client\n");

-		return;

-	}

-		

-	client = &svs.clients[entnum-1];

-		

-	MSG_WriteChar (&client->message,svc_print);

-	MSG_WriteString (&client->message, s );

-}

-

-

-/*

-=================

-PF_centerprint

-

-single print to a specific client

-

-centerprint(clientent, value)

-=================

-*/

-void PF_centerprint (void)

-{

-	char		*s;

-	client_t	*client;

-	int			entnum;

-	

-	entnum = G_EDICTNUM(OFS_PARM0);

-	s = PF_VarString(1);

-	

-	if (entnum < 1 || entnum > svs.maxclients)

-	{

-		Con_Printf ("tried to sprint to a non-client\n");

-		return;

-	}

-		

-	client = &svs.clients[entnum-1];

-		

-	MSG_WriteChar (&client->message,svc_centerprint);

-	MSG_WriteString (&client->message, s );

-}

-

-

-/*

-=================

-PF_normalize

-

-vector normalize(vector)

-=================

-*/

-void PF_normalize (void)

-{

-	float	*value1;

-	vec3_t	newvalue;

-	float	new;

-	

-	value1 = G_VECTOR(OFS_PARM0);

-

-	new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];

-	new = sqrt(new);

-	

-	if (new == 0)

-		newvalue[0] = newvalue[1] = newvalue[2] = 0;

-	else

-	{

-		new = 1/new;

-		newvalue[0] = value1[0] * new;

-		newvalue[1] = value1[1] * new;

-		newvalue[2] = value1[2] * new;

-	}

-	

-	VectorCopy (newvalue, G_VECTOR(OFS_RETURN));	

-}

-

-/*

-=================

-PF_vlen

-

-scalar vlen(vector)

-=================

-*/

-void PF_vlen (void)

-{

-	float	*value1;

-	float	new;

-	

-	value1 = G_VECTOR(OFS_PARM0);

-

-	new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];

-	new = sqrt(new);

-	

-	G_FLOAT(OFS_RETURN) = new;

-}

-

-/*

-=================

-PF_vectoyaw

-

-float vectoyaw(vector)

-=================

-*/

-void PF_vectoyaw (void)

-{

-	float	*value1;

-	float	yaw;

-	

-	value1 = G_VECTOR(OFS_PARM0);

-

-	if (value1[1] == 0 && value1[0] == 0)

-		yaw = 0;

-	else

-	{

-		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);

-		if (yaw < 0)

-			yaw += 360;

-	}

-

-	G_FLOAT(OFS_RETURN) = yaw;

-}

-

-

-/*

-=================

-PF_vectoangles

-

-vector vectoangles(vector)

-=================

-*/

-void PF_vectoangles (void)

-{

-	float	*value1;

-	float	forward;

-	float	yaw, pitch;

-	

-	value1 = G_VECTOR(OFS_PARM0);

-

-	if (value1[1] == 0 && value1[0] == 0)

-	{

-		yaw = 0;

-		if (value1[2] > 0)

-			pitch = 90;

-		else

-			pitch = 270;

-	}

-	else

-	{

-		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);

-		if (yaw < 0)

-			yaw += 360;

-

-		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);

-		pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);

-		if (pitch < 0)

-			pitch += 360;

-	}

-

-	G_FLOAT(OFS_RETURN+0) = pitch;

-	G_FLOAT(OFS_RETURN+1) = yaw;

-	G_FLOAT(OFS_RETURN+2) = 0;

-}

-

-/*

-=================

-PF_Random

-

-Returns a number from 0<= num < 1

-

-random()

-=================

-*/

-void PF_random (void)

-{

-	float		num;

-		

-	num = (rand ()&0x7fff) / ((float)0x7fff);

-	

-	G_FLOAT(OFS_RETURN) = num;

-}

-

-/*

-=================

-PF_particle

-

-particle(origin, color, count)

-=================

-*/

-void PF_particle (void)

-{

-	float		*org, *dir;

-	float		color;

-	float		count;

-			

-	org = G_VECTOR(OFS_PARM0);

-	dir = G_VECTOR(OFS_PARM1);

-	color = G_FLOAT(OFS_PARM2);

-	count = G_FLOAT(OFS_PARM3);

-	SV_StartParticle (org, dir, color, count);

-}

-

-

-/*

-=================

-PF_ambientsound

-

-=================

-*/

-void PF_ambientsound (void)

-{

-	char		**check;

-	char		*samp;

-	float		*pos;

-	float 		vol, attenuation;

-	int			i, soundnum;

-

-	pos = G_VECTOR (OFS_PARM0);			

-	samp = G_STRING(OFS_PARM1);

-	vol = G_FLOAT(OFS_PARM2);

-	attenuation = G_FLOAT(OFS_PARM3);

-	

-// check to see if samp was properly precached

-	for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)

-		if (!strcmp(*check,samp))

-			break;

-			

-	if (!*check)

-	{

-		Con_Printf ("no precache: %s\n", samp);

-		return;

-	}

-

-// add an svc_spawnambient command to the level signon packet

-

-	MSG_WriteByte (&sv.signon,svc_spawnstaticsound);

-	for (i=0 ; i<3 ; i++)

-		MSG_WriteCoord(&sv.signon, pos[i]);

-

-	MSG_WriteByte (&sv.signon, soundnum);

-

-	MSG_WriteByte (&sv.signon, vol*255);

-	MSG_WriteByte (&sv.signon, attenuation*64);

-

-}

-

-/*

-=================

-PF_sound

-

-Each entity can have eight independant sound sources, like voice,

-weapon, feet, etc.

-

-Channel 0 is an auto-allocate channel, the others override anything

-allready running on that entity/channel pair.

-

-An attenuation of 0 will play full volume everywhere in the level.

-Larger attenuations will drop off.

-

-=================

-*/

-void PF_sound (void)

-{

-	char		*sample;

-	int			channel;

-	edict_t		*entity;

-	int 		volume;

-	float attenuation;

-		

-	entity = G_EDICT(OFS_PARM0);

-	channel = G_FLOAT(OFS_PARM1);

-	sample = G_STRING(OFS_PARM2);

-	volume = G_FLOAT(OFS_PARM3) * 255;

-	attenuation = G_FLOAT(OFS_PARM4);

-	

-	if (volume < 0 || volume > 255)

-		Sys_Error ("SV_StartSound: volume = %i", volume);

-

-	if (attenuation < 0 || attenuation > 4)

-		Sys_Error ("SV_StartSound: attenuation = %f", attenuation);

-

-	if (channel < 0 || channel > 7)

-		Sys_Error ("SV_StartSound: channel = %i", channel);

-

-	SV_StartSound (entity, channel, sample, volume, attenuation);

-}

-

-/*

-=================

-PF_break

-

-break()

-=================

-*/

-void PF_break (void)

-{

-Con_Printf ("break statement\n");

-*(int *)-4 = 0;	// dump to debugger

-//	PR_RunError ("break statement");

-}

-

-/*

-=================

-PF_traceline

-

-Used for use tracing and shot targeting

-Traces are blocked by bbox and exact bsp entityes, and also slide box entities

-if the tryents flag is set.

-

-traceline (vector1, vector2, tryents)

-=================

-*/

-void PF_traceline (void)

-{

-	float	*v1, *v2;

-	trace_t	trace;

-	int		nomonsters;

-	edict_t	*ent;

-

-	v1 = G_VECTOR(OFS_PARM0);

-	v2 = G_VECTOR(OFS_PARM1);

-	nomonsters = G_FLOAT(OFS_PARM2);

-	ent = G_EDICT(OFS_PARM3);

-

-	trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);

-

-	pr_global_struct->trace_allsolid = trace.allsolid;

-	pr_global_struct->trace_startsolid = trace.startsolid;

-	pr_global_struct->trace_fraction = trace.fraction;

-	pr_global_struct->trace_inwater = trace.inwater;

-	pr_global_struct->trace_inopen = trace.inopen;

-	VectorCopy (trace.endpos, pr_global_struct->trace_endpos);

-	VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);

-	pr_global_struct->trace_plane_dist =  trace.plane.dist;	

-	if (trace.ent)

-		pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);

-	else

-		pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);

-}

-

-

-#ifdef QUAKE2

-extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);

-

-void PF_TraceToss (void)

-{

-	trace_t	trace;

-	edict_t	*ent;

-	edict_t	*ignore;

-

-	ent = G_EDICT(OFS_PARM0);

-	ignore = G_EDICT(OFS_PARM1);

-

-	trace = SV_Trace_Toss (ent, ignore);

-

-	pr_global_struct->trace_allsolid = trace.allsolid;

-	pr_global_struct->trace_startsolid = trace.startsolid;

-	pr_global_struct->trace_fraction = trace.fraction;

-	pr_global_struct->trace_inwater = trace.inwater;

-	pr_global_struct->trace_inopen = trace.inopen;

-	VectorCopy (trace.endpos, pr_global_struct->trace_endpos);

-	VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);

-	pr_global_struct->trace_plane_dist =  trace.plane.dist;	

-	if (trace.ent)

-		pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);

-	else

-		pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);

-}

-#endif

-

-

-/*

-=================

-PF_checkpos

-

-Returns true if the given entity can move to the given position from it's

-current position by walking or rolling.

-FIXME: make work...

-scalar checkpos (entity, vector)

-=================

-*/

-void PF_checkpos (void)

-{

-}

-

-//============================================================================

-

-byte	checkpvs[MAX_MAP_LEAFS/8];

-

-int PF_newcheckclient (int check)

-{

-	int		i;

-	byte	*pvs;

-	edict_t	*ent;

-	mleaf_t	*leaf;

-	vec3_t	org;

-

-// cycle to the next one

-

-	if (check < 1)

-		check = 1;

-	if (check > svs.maxclients)

-		check = svs.maxclients;

-

-	if (check == svs.maxclients)

-		i = 1;

-	else

-		i = check + 1;

-

-	for ( ;  ; i++)

-	{

-		if (i == svs.maxclients+1)

-			i = 1;

-

-		ent = EDICT_NUM(i);

-

-		if (i == check)

-			break;	// didn't find anything else

-

-		if (ent->free)

-			continue;

-		if (ent->v.health <= 0)

-			continue;

-		if ((int)ent->v.flags & FL_NOTARGET)

-			continue;

-

-	// anything that is a client, or has a client as an enemy

-		break;

-	}

-

-// get the PVS for the entity

-	VectorAdd (ent->v.origin, ent->v.view_ofs, org);

-	leaf = Mod_PointInLeaf (org, sv.worldmodel);

-	pvs = Mod_LeafPVS (leaf, sv.worldmodel);

-	memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );

-

-	return i;

-}

-

-/*

-=================

-PF_checkclient

-

-Returns a client (or object that has a client enemy) that would be a

-valid target.

-

-If there are more than one valid options, they are cycled each frame

-

-If (self.origin + self.viewofs) is not in the PVS of the current target,

-it is not returned at all.

-

-name checkclient ()

-=================

-*/

-#define	MAX_CHECK	16

-int c_invis, c_notvis;

-void PF_checkclient (void)

-{

-	edict_t	*ent, *self;

-	mleaf_t	*leaf;

-	int		l;

-	vec3_t	view;

-	

-// find a new check if on a new frame

-	if (sv.time - sv.lastchecktime >= 0.1)

-	{

-		sv.lastcheck = PF_newcheckclient (sv.lastcheck);

-		sv.lastchecktime = sv.time;

-	}

-

-// return check if it might be visible	

-	ent = EDICT_NUM(sv.lastcheck);

-	if (ent->free || ent->v.health <= 0)

-	{

-		RETURN_EDICT(sv.edicts);

-		return;

-	}

-

-// if current entity can't possibly see the check entity, return 0

-	self = PROG_TO_EDICT(pr_global_struct->self);

-	VectorAdd (self->v.origin, self->v.view_ofs, view);

-	leaf = Mod_PointInLeaf (view, sv.worldmodel);

-	l = (leaf - sv.worldmodel->leafs) - 1;

-	if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )

-	{

-c_notvis++;

-		RETURN_EDICT(sv.edicts);

-		return;

-	}

-

-// might be able to see it

-c_invis++;

-	RETURN_EDICT(ent);

-}

-

-//============================================================================

-

-

-/*

-=================

-PF_stuffcmd

-

-Sends text over to the client's execution buffer

-

-stuffcmd (clientent, value)

-=================

-*/

-void PF_stuffcmd (void)

-{

-	int		entnum;

-	char	*str;

-	client_t	*old;

-	

-	entnum = G_EDICTNUM(OFS_PARM0);

-	if (entnum < 1 || entnum > svs.maxclients)

-		PR_RunError ("Parm 0 not a client");

-	str = G_STRING(OFS_PARM1);	

-	

-	old = host_client;

-	host_client = &svs.clients[entnum-1];

-	Host_ClientCommands ("%s", str);

-	host_client = old;

-}

-

-/*

-=================

-PF_localcmd

-

-Sends text over to the client's execution buffer

-

-localcmd (string)

-=================

-*/

-void PF_localcmd (void)

-{

-	char	*str;

-	

-	str = G_STRING(OFS_PARM0);	

-	Cbuf_AddText (str);

-}

-

-/*

-=================

-PF_cvar

-

-float cvar (string)

-=================

-*/

-void PF_cvar (void)

-{

-	char	*str;

-	

-	str = G_STRING(OFS_PARM0);

-	

-	G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);

-}

-

-/*

-=================

-PF_cvar_set

-

-float cvar (string)

-=================

-*/

-void PF_cvar_set (void)

-{

-	char	*var, *val;

-	

-	var = G_STRING(OFS_PARM0);

-	val = G_STRING(OFS_PARM1);

-	

-	Cvar_Set (var, val);

-}

-

-/*

-=================

-PF_findradius

-

-Returns a chain of entities that have origins within a spherical area

-

-findradius (origin, radius)

-=================

-*/

-void PF_findradius (void)

-{

-	edict_t	*ent, *chain;

-	float	rad;

-	float	*org;

-	vec3_t	eorg;

-	int		i, j;

-

-	chain = (edict_t *)sv.edicts;

-	

-	org = G_VECTOR(OFS_PARM0);

-	rad = G_FLOAT(OFS_PARM1);

-

-	ent = NEXT_EDICT(sv.edicts);

-	for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))

-	{

-		if (ent->free)

-			continue;

-		if (ent->v.solid == SOLID_NOT)

-			continue;

-		for (j=0 ; j<3 ; j++)

-			eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);			

-		if (Length(eorg) > rad)

-			continue;

-			

-		ent->v.chain = EDICT_TO_PROG(chain);

-		chain = ent;

-	}

-

-	RETURN_EDICT(chain);

-}

-

-

-/*

-=========

-PF_dprint

-=========

-*/

-void PF_dprint (void)

-{

-	Con_DPrintf ("%s",PF_VarString(0));

-}

-

-char	pr_string_temp[128];

-

-void PF_ftos (void)

-{

-	float	v;

-	v = G_FLOAT(OFS_PARM0);

-	

-	if (v == (int)v)

-		sprintf (pr_string_temp, "%d",(int)v);

-	else

-		sprintf (pr_string_temp, "%5.1f",v);

-	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;

-}

-

-void PF_fabs (void)

-{

-	float	v;

-	v = G_FLOAT(OFS_PARM0);

-	G_FLOAT(OFS_RETURN) = fabs(v);

-}

-

-void PF_vtos (void)

-{

-	sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);

-	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;

-}

-

-#ifdef QUAKE2

-void PF_etos (void)

-{

-	sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0));

-	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;

-}

-#endif

-

-void PF_Spawn (void)

-{

-	edict_t	*ed;

-	ed = ED_Alloc();

-	RETURN_EDICT(ed);

-}

-

-void PF_Remove (void)

-{

-	edict_t	*ed;

-	

-	ed = G_EDICT(OFS_PARM0);

-	ED_Free (ed);

-}

-

-

-// entity (entity start, .string field, string match) find = #5;

-void PF_Find (void)

-#ifdef QUAKE2

-{

-	int		e;	

-	int		f;

-	char	*s, *t;

-	edict_t	*ed;

-	edict_t	*first;

-	edict_t	*second;

-	edict_t	*last;

-

-	first = second = last = (edict_t *)sv.edicts;

-	e = G_EDICTNUM(OFS_PARM0);

-	f = G_INT(OFS_PARM1);

-	s = G_STRING(OFS_PARM2);

-	if (!s)

-		PR_RunError ("PF_Find: bad search string");

-		

-	for (e++ ; e < sv.num_edicts ; e++)

-	{

-		ed = EDICT_NUM(e);

-		if (ed->free)

-			continue;

-		t = E_STRING(ed,f);

-		if (!t)

-			continue;

-		if (!strcmp(t,s))

-		{

-			if (first == (edict_t *)sv.edicts)

-				first = ed;

-			else if (second == (edict_t *)sv.edicts)

-				second = ed;

-			ed->v.chain = EDICT_TO_PROG(last);

-			last = ed;

-		}

-	}

-

-	if (first != last)

-	{

-		if (last != second)

-			first->v.chain = last->v.chain;

-		else

-			first->v.chain = EDICT_TO_PROG(last);

-		last->v.chain = EDICT_TO_PROG((edict_t *)sv.edicts);

-		if (second && second != last)

-			second->v.chain = EDICT_TO_PROG(last);

-	}

-	RETURN_EDICT(first);

-}

-#else

-{

-	int		e;	

-	int		f;

-	char	*s, *t;

-	edict_t	*ed;

-

-	e = G_EDICTNUM(OFS_PARM0);

-	f = G_INT(OFS_PARM1);

-	s = G_STRING(OFS_PARM2);

-	if (!s)

-		PR_RunError ("PF_Find: bad search string");

-		

-	for (e++ ; e < sv.num_edicts ; e++)

-	{

-		ed = EDICT_NUM(e);

-		if (ed->free)

-			continue;

-		t = E_STRING(ed,f);

-		if (!t)

-			continue;

-		if (!strcmp(t,s))

-		{

-			RETURN_EDICT(ed);

-			return;

-		}

-	}

-

-	RETURN_EDICT(sv.edicts);

-}

-#endif

-

-void PR_CheckEmptyString (char *s)

-{

-	if (s[0] <= ' ')

-		PR_RunError ("Bad string");

-}

-

-void PF_precache_file (void)

-{	// precache_file is only used to copy files with qcc, it does nothing

-	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);

-}

-

-void PF_precache_sound (void)

-{

-	char	*s;

-	int		i;

-	

-	if (sv.state != ss_loading)

-		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");

-		

-	s = G_STRING(OFS_PARM0);

-	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);

-	PR_CheckEmptyString (s);

-	

-	for (i=0 ; i<MAX_SOUNDS ; i++)

-	{

-		if (!sv.sound_precache[i])

-		{

-			sv.sound_precache[i] = s;

-			return;

-		}

-		if (!strcmp(sv.sound_precache[i], s))

-			return;

-	}

-	PR_RunError ("PF_precache_sound: overflow");

-}

-

-void PF_precache_model (void)

-{

-	char	*s;

-	int		i;

-	

-	if (sv.state != ss_loading)

-		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");

-		

-	s = G_STRING(OFS_PARM0);

-	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);

-	PR_CheckEmptyString (s);

-

-	for (i=0 ; i<MAX_MODELS ; i++)

-	{

-		if (!sv.model_precache[i])

-		{

-			sv.model_precache[i] = s;

-			sv.models[i] = Mod_ForName (s, true);

-			return;

-		}

-		if (!strcmp(sv.model_precache[i], s))

-			return;

-	}

-	PR_RunError ("PF_precache_model: overflow");

-}

-

-

-void PF_coredump (void)

-{

-	ED_PrintEdicts ();

-}

-

-void PF_traceon (void)

-{

-	pr_trace = true;

-}

-

-void PF_traceoff (void)

-{

-	pr_trace = false;

-}

-

-void PF_eprint (void)

-{

-	ED_PrintNum (G_EDICTNUM(OFS_PARM0));

-}

-

-/*

-===============

-PF_walkmove

-

-float(float yaw, float dist) walkmove

-===============

-*/

-void PF_walkmove (void)

-{

-	edict_t	*ent;

-	float	yaw, dist;

-	vec3_t	move;

-	dfunction_t	*oldf;

-	int 	oldself;

-	

-	ent = PROG_TO_EDICT(pr_global_struct->self);

-	yaw = G_FLOAT(OFS_PARM0);

-	dist = G_FLOAT(OFS_PARM1);

-	

-	if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )

-	{

-		G_FLOAT(OFS_RETURN) = 0;

-		return;

-	}

-

-	yaw = yaw*M_PI*2 / 360;

-	

-	move[0] = cos(yaw)*dist;

-	move[1] = sin(yaw)*dist;

-	move[2] = 0;

-

-// save program state, because SV_movestep may call other progs

-	oldf = pr_xfunction;

-	oldself = pr_global_struct->self;

-	

-	G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);

-	

-	

-// restore program state

-	pr_xfunction = oldf;

-	pr_global_struct->self = oldself;

-}

-

-/*

-===============

-PF_droptofloor

-

-void() droptofloor

-===============

-*/

-void PF_droptofloor (void)

-{

-	edict_t		*ent;

-	vec3_t		end;

-	trace_t		trace;

-	

-	ent = PROG_TO_EDICT(pr_global_struct->self);

-

-	VectorCopy (ent->v.origin, end);

-	end[2] -= 256;

-	

-	trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);

-

-	if (trace.fraction == 1 || trace.allsolid)

-		G_FLOAT(OFS_RETURN) = 0;

-	else

-	{

-		VectorCopy (trace.endpos, ent->v.origin);

-		SV_LinkEdict (ent, false);

-		ent->v.flags = (int)ent->v.flags | FL_ONGROUND;

-		ent->v.groundentity = EDICT_TO_PROG(trace.ent);

-		G_FLOAT(OFS_RETURN) = 1;

-	}

-}

-

-/*

-===============

-PF_lightstyle

-

-void(float style, string value) lightstyle

-===============

-*/

-void PF_lightstyle (void)

-{

-	int		style;

-	char	*val;

-	client_t	*client;

-	int			j;

-	

-	style = G_FLOAT(OFS_PARM0);

-	val = G_STRING(OFS_PARM1);

-

-// change the string in sv

-	sv.lightstyles[style] = val;

-	

-// send message to all clients on this server

-	if (sv.state != ss_active)

-		return;

-	

-	for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)

-		if (client->active || client->spawned)

-		{

-			MSG_WriteChar (&client->message, svc_lightstyle);

-			MSG_WriteChar (&client->message,style);

-			MSG_WriteString (&client->message, val);

-		}

-}

-

-void PF_rint (void)

-{

-	float	f;

-	f = G_FLOAT(OFS_PARM0);

-	if (f > 0)

-		G_FLOAT(OFS_RETURN) = (int)(f + 0.5);

-	else

-		G_FLOAT(OFS_RETURN) = (int)(f - 0.5);

-}

-void PF_floor (void)

-{

-	G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));

-}

-void PF_ceil (void)

-{

-	G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));

-}

-

-

-/*

-=============

-PF_checkbottom

-=============

-*/

-void PF_checkbottom (void)

-{

-	edict_t	*ent;

-	

-	ent = G_EDICT(OFS_PARM0);

-

-	G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);

-}

-

-/*

-=============

-PF_pointcontents

-=============

-*/

-void PF_pointcontents (void)

-{

-	float	*v;

-	

-	v = G_VECTOR(OFS_PARM0);

-

-	G_FLOAT(OFS_RETURN) = SV_PointContents (v);	

-}

-

-/*

-=============

-PF_nextent

-

-entity nextent(entity)

-=============

-*/

-void PF_nextent (void)

-{

-	int		i;

-	edict_t	*ent;

-	

-	i = G_EDICTNUM(OFS_PARM0);

-	while (1)

-	{

-		i++;

-		if (i == sv.num_edicts)

-		{

-			RETURN_EDICT(sv.edicts);

-			return;

-		}

-		ent = EDICT_NUM(i);

-		if (!ent->free)

-		{

-			RETURN_EDICT(ent);

-			return;

-		}

-	}

-}

-

-/*

-=============

-PF_aim

-

-Pick a vector for the player to shoot along

-vector aim(entity, missilespeed)

-=============

-*/

-cvar_t	sv_aim = {"sv_aim", "0.93"};

-void PF_aim (void)

-{

-	edict_t	*ent, *check, *bestent;

-	vec3_t	start, dir, end, bestdir;

-	int		i, j;

-	trace_t	tr;

-	float	dist, bestdist;

-	float	speed;

-	

-	ent = G_EDICT(OFS_PARM0);

-	speed = G_FLOAT(OFS_PARM1);

-

-	VectorCopy (ent->v.origin, start);

-	start[2] += 20;

-

-// try sending a trace straight

-	VectorCopy (pr_global_struct->v_forward, dir);

-	VectorMA (start, 2048, dir, end);

-	tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);

-	if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM

-	&& (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )

-	{

-		VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));

-		return;

-	}

-

-

-// try all possible entities

-	VectorCopy (dir, bestdir);

-	bestdist = sv_aim.value;

-	bestent = NULL;

-	

-	check = NEXT_EDICT(sv.edicts);

-	for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )

-	{

-		if (check->v.takedamage != DAMAGE_AIM)

-			continue;

-		if (check == ent)

-			continue;

-		if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)

-			continue;	// don't aim at teammate

-		for (j=0 ; j<3 ; j++)

-			end[j] = check->v.origin[j]

-			+ 0.5*(check->v.mins[j] + check->v.maxs[j]);

-		VectorSubtract (end, start, dir);

-		VectorNormalize (dir);

-		dist = DotProduct (dir, pr_global_struct->v_forward);

-		if (dist < bestdist)

-			continue;	// to far to turn

-		tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);

-		if (tr.ent == check)

-		{	// can shoot at this one

-			bestdist = dist;

-			bestent = check;

-		}

-	}

-	

-	if (bestent)

-	{

-		VectorSubtract (bestent->v.origin, ent->v.origin, dir);

-		dist = DotProduct (dir, pr_global_struct->v_forward);

-		VectorScale (pr_global_struct->v_forward, dist, end);

-		end[2] = dir[2];

-		VectorNormalize (end);

-		VectorCopy (end, G_VECTOR(OFS_RETURN));	

-	}

-	else

-	{

-		VectorCopy (bestdir, G_VECTOR(OFS_RETURN));

-	}

-}

-

-/*

-==============

-PF_changeyaw

-

-This was a major timewaster in progs, so it was converted to C

-==============

-*/

-void PF_changeyaw (void)

-{

-	edict_t		*ent;

-	float		ideal, current, move, speed;

-	

-	ent = PROG_TO_EDICT(pr_global_struct->self);

-	current = anglemod( ent->v.angles[1] );

-	ideal = ent->v.ideal_yaw;

-	speed = ent->v.yaw_speed;

-	

-	if (current == ideal)

-		return;

-	move = ideal - current;

-	if (ideal > current)

-	{

-		if (move >= 180)

-			move = move - 360;

-	}

-	else

-	{

-		if (move <= -180)

-			move = move + 360;

-	}

-	if (move > 0)

-	{

-		if (move > speed)

-			move = speed;

-	}

-	else

-	{

-		if (move < -speed)

-			move = -speed;

-	}

-	

-	ent->v.angles[1] = anglemod (current + move);

-}

-

-#ifdef QUAKE2

-/*

-==============

-PF_changepitch

-==============

-*/

-void PF_changepitch (void)

-{

-	edict_t		*ent;

-	float		ideal, current, move, speed;

-	

-	ent = G_EDICT(OFS_PARM0);

-	current = anglemod( ent->v.angles[0] );

-	ideal = ent->v.idealpitch;

-	speed = ent->v.pitch_speed;

-	

-	if (current == ideal)

-		return;

-	move = ideal - current;

-	if (ideal > current)

-	{

-		if (move >= 180)

-			move = move - 360;

-	}

-	else

-	{

-		if (move <= -180)

-			move = move + 360;

-	}

-	if (move > 0)

-	{

-		if (move > speed)

-			move = speed;

-	}

-	else

-	{

-		if (move < -speed)

-			move = -speed;

-	}

-	

-	ent->v.angles[0] = anglemod (current + move);

-}

-#endif

-

-/*

-===============================================================================

-

-MESSAGE WRITING

-

-===============================================================================

-*/

-

-#define	MSG_BROADCAST	0		// unreliable to all

-#define	MSG_ONE			1		// reliable to one (msg_entity)

-#define	MSG_ALL			2		// reliable to all

-#define	MSG_INIT		3		// write to the init string

-

-sizebuf_t *WriteDest (void)

-{

-	int		entnum;

-	int		dest;

-	edict_t	*ent;

-

-	dest = G_FLOAT(OFS_PARM0);

-	switch (dest)

-	{

-	case MSG_BROADCAST:

-		return &sv.datagram;

-	

-	case MSG_ONE:

-		ent = PROG_TO_EDICT(pr_global_struct->msg_entity);

-		entnum = NUM_FOR_EDICT(ent);

-		if (entnum < 1 || entnum > svs.maxclients)

-			PR_RunError ("WriteDest: not a client");

-		return &svs.clients[entnum-1].message;

-		

-	case MSG_ALL:

-		return &sv.reliable_datagram;

-	

-	case MSG_INIT:

-		return &sv.signon;

-

-	default:

-		PR_RunError ("WriteDest: bad destination");

-		break;

-	}

-	

-	return NULL;

-}

-

-void PF_WriteByte (void)

-{

-	MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));

-}

-

-void PF_WriteChar (void)

-{

-	MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));

-}

-

-void PF_WriteShort (void)

-{

-	MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));

-}

-

-void PF_WriteLong (void)

-{

-	MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));

-}

-

-void PF_WriteAngle (void)

-{

-	MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));

-}

-

-void PF_WriteCoord (void)

-{

-	MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));

-}

-

-void PF_WriteString (void)

-{

-	MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));

-}

-

-

-void PF_WriteEntity (void)

-{

-	MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));

-}

-

-//=============================================================================

-

-int SV_ModelIndex (char *name);

-

-void PF_makestatic (void)

-{

-	edict_t	*ent;

-	int		i;

-	

-	ent = G_EDICT(OFS_PARM0);

-

-	MSG_WriteByte (&sv.signon,svc_spawnstatic);

-

-	MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));

-

-	MSG_WriteByte (&sv.signon, ent->v.frame);

-	MSG_WriteByte (&sv.signon, ent->v.colormap);

-	MSG_WriteByte (&sv.signon, ent->v.skin);

-	for (i=0 ; i<3 ; i++)

-	{

-		MSG_WriteCoord(&sv.signon, ent->v.origin[i]);

-		MSG_WriteAngle(&sv.signon, ent->v.angles[i]);

-	}

-

-// throw the entity away now

-	ED_Free (ent);

-}

-

-//=============================================================================

-

-/*

-==============

-PF_setspawnparms

-==============

-*/

-void PF_setspawnparms (void)

-{

-	edict_t	*ent;

-	int		i;

-	client_t	*client;

-

-	ent = G_EDICT(OFS_PARM0);

-	i = NUM_FOR_EDICT(ent);

-	if (i < 1 || i > svs.maxclients)

-		PR_RunError ("Entity is not a client");

-

-	// copy spawn parms out of the client_t

-	client = svs.clients + (i-1);

-

-	for (i=0 ; i< NUM_SPAWN_PARMS ; i++)

-		(&pr_global_struct->parm1)[i] = client->spawn_parms[i];

-}

-

-/*

-==============

-PF_changelevel

-==============

-*/

-void PF_changelevel (void)

-{

-#ifdef QUAKE2

-	char	*s1, *s2;

-

-	if (svs.changelevel_issued)

-		return;

-	svs.changelevel_issued = true;

-

-	s1 = G_STRING(OFS_PARM0);

-	s2 = G_STRING(OFS_PARM1);

-

-	if ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE))

-		Cbuf_AddText (va("changelevel %s %s\n",s1, s2));

-	else

-		Cbuf_AddText (va("changelevel2 %s %s\n",s1, s2));

-#else

-	char	*s;

-

-// make sure we don't issue two changelevels

-	if (svs.changelevel_issued)

-		return;

-	svs.changelevel_issued = true;

-	

-	s = G_STRING(OFS_PARM0);

-	Cbuf_AddText (va("changelevel %s\n",s));

-#endif

-}

-

-

-#ifdef QUAKE2

-

-#define	CONTENT_WATER	-3

-#define CONTENT_SLIME	-4

-#define CONTENT_LAVA	-5

-

-#define FL_IMMUNE_WATER	131072

-#define	FL_IMMUNE_SLIME	262144

-#define FL_IMMUNE_LAVA	524288

-

-#define	CHAN_VOICE	2

-#define	CHAN_BODY	4

-

-#define	ATTN_NORM	1

-

-void PF_WaterMove (void)

-{

-	edict_t		*self;

-	int			flags;

-	int			waterlevel;

-	int			watertype;

-	float		drownlevel;

-	float		damage = 0.0;

-

-	self = PROG_TO_EDICT(pr_global_struct->self);

-

-	if (self->v.movetype == MOVETYPE_NOCLIP)

-	{

-		self->v.air_finished = sv.time + 12;

-		G_FLOAT(OFS_RETURN) = damage;

-		return;

-	}

-

-	if (self->v.health < 0)

-	{

-		G_FLOAT(OFS_RETURN) = damage;

-		return;

-	}

-

-	if (self->v.deadflag == DEAD_NO)

-		drownlevel = 3;

-	else

-		drownlevel = 1;

-

-	flags = (int)self->v.flags;

-	waterlevel = (int)self->v.waterlevel;

-	watertype = (int)self->v.watertype;

-

-	if (!(flags & (FL_IMMUNE_WATER + FL_GODMODE)))

-		if (((flags & FL_SWIM) && (waterlevel < drownlevel)) || (waterlevel >= drownlevel))

-		{

-			if (self->v.air_finished < sv.time)

-				if (self->v.pain_finished < sv.time)

-				{

-					self->v.dmg = self->v.dmg + 2;

-					if (self->v.dmg > 15)

-						self->v.dmg = 10;

-//					T_Damage (self, world, world, self.dmg, 0, FALSE);

-					damage = self->v.dmg;

-					self->v.pain_finished = sv.time + 1.0;

-				}

-		}

-		else

-		{

-			if (self->v.air_finished < sv.time)

-//				sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);

-				SV_StartSound (self, CHAN_VOICE, "player/gasp2.wav", 255, ATTN_NORM);

-			else if (self->v.air_finished < sv.time + 9)

-//				sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);

-				SV_StartSound (self, CHAN_VOICE, "player/gasp1.wav", 255, ATTN_NORM);

-			self->v.air_finished = sv.time + 12.0;

-			self->v.dmg = 2;

-		}

-	

-	if (!waterlevel)

-	{

-		if (flags & FL_INWATER)

-		{	

-			// play leave water sound

-//			sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);

-			SV_StartSound (self, CHAN_BODY, "misc/outwater.wav", 255, ATTN_NORM);

-			self->v.flags = (float)(flags &~FL_INWATER);

-		}

-		self->v.air_finished = sv.time + 12.0;

-		G_FLOAT(OFS_RETURN) = damage;

-		return;

-	}

-

-	if (watertype == CONTENT_LAVA)

-	{	// do damage

-		if (!(flags & (FL_IMMUNE_LAVA + FL_GODMODE)))

-			if (self->v.dmgtime < sv.time)

-			{

-				if (self->v.radsuit_finished < sv.time)

-					self->v.dmgtime = sv.time + 0.2;

-				else

-					self->v.dmgtime = sv.time + 1.0;

-//				T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE);

-				damage = (float)(10*waterlevel);

-			}

-	}

-	else if (watertype == CONTENT_SLIME)

-	{	// do damage

-		if (!(flags & (FL_IMMUNE_SLIME + FL_GODMODE)))

-			if (self->v.dmgtime < sv.time && self->v.radsuit_finished < sv.time)

-			{

-				self->v.dmgtime = sv.time + 1.0;

-//				T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE);

-				damage = (float)(4*waterlevel);

-			}

-	}

-	

-	if ( !(flags & FL_INWATER) )

-	{	

-

-// player enter water sound

-		if (watertype == CONTENT_LAVA)

-//			sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);

-			SV_StartSound (self, CHAN_BODY, "player/inlava.wav", 255, ATTN_NORM);

-		if (watertype == CONTENT_WATER)

-//			sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);

-			SV_StartSound (self, CHAN_BODY, "player/inh2o.wav", 255, ATTN_NORM);

-		if (watertype == CONTENT_SLIME)

-//			sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);

-			SV_StartSound (self, CHAN_BODY, "player/slimbrn2.wav", 255, ATTN_NORM);

-

-		self->v.flags = (float)(flags | FL_INWATER);

-		self->v.dmgtime = 0;

-	}

-	

-	if (! (flags & FL_WATERJUMP) )

-	{

-//		self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;

-		VectorMA (self->v.velocity, -0.8 * self->v.waterlevel * host_frametime, self->v.velocity, self->v.velocity);

-	}

-

-	G_FLOAT(OFS_RETURN) = damage;

-}

-

-

-void PF_sin (void)

-{

-	G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));

-}

-

-void PF_cos (void)

-{

-	G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));

-}

-

-void PF_sqrt (void)

-{

-	G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));

-}

-#endif

-

-void PF_Fixme (void)

-{

-	PR_RunError ("unimplemented bulitin");

-}

-

-

-

-builtin_t pr_builtin[] =

-{

-PF_Fixme,

-PF_makevectors,	// void(entity e)	makevectors 		= #1;

-PF_setorigin,	// void(entity e, vector o) setorigin	= #2;

-PF_setmodel,	// void(entity e, string m) setmodel	= #3;

-PF_setsize,	// void(entity e, vector min, vector max) setsize = #4;

-PF_Fixme,	// void(entity e, vector min, vector max) setabssize = #5;

-PF_break,	// void() break						= #6;

-PF_random,	// float() random						= #7;

-PF_sound,	// void(entity e, float chan, string samp) sound = #8;

-PF_normalize,	// vector(vector v) normalize			= #9;

-PF_error,	// void(string e) error				= #10;

-PF_objerror,	// void(string e) objerror				= #11;

-PF_vlen,	// float(vector v) vlen				= #12;

-PF_vectoyaw,	// float(vector v) vectoyaw		= #13;

-PF_Spawn,	// entity() spawn						= #14;

-PF_Remove,	// void(entity e) remove				= #15;

-PF_traceline,	// float(vector v1, vector v2, float tryents) traceline = #16;

-PF_checkclient,	// entity() clientlist					= #17;

-PF_Find,	// entity(entity start, .string fld, string match) find = #18;

-PF_precache_sound,	// void(string s) precache_sound		= #19;

-PF_precache_model,	// void(string s) precache_model		= #20;

-PF_stuffcmd,	// void(entity client, string s)stuffcmd = #21;

-PF_findradius,	// entity(vector org, float rad) findradius = #22;

-PF_bprint,	// void(string s) bprint				= #23;

-PF_sprint,	// void(entity client, string s) sprint = #24;

-PF_dprint,	// void(string s) dprint				= #25;

-PF_ftos,	// void(string s) ftos				= #26;

-PF_vtos,	// void(string s) vtos				= #27;

-PF_coredump,

-PF_traceon,

-PF_traceoff,

-PF_eprint,	// void(entity e) debug print an entire entity

-PF_walkmove, // float(float yaw, float dist) walkmove

-PF_Fixme, // float(float yaw, float dist) walkmove

-PF_droptofloor,

-PF_lightstyle,

-PF_rint,

-PF_floor,

-PF_ceil,

-PF_Fixme,

-PF_checkbottom,

-PF_pointcontents,

-PF_Fixme,

-PF_fabs,

-PF_aim,

-PF_cvar,

-PF_localcmd,

-PF_nextent,

-PF_particle,

-PF_changeyaw,

-PF_Fixme,

-PF_vectoangles,

-

-PF_WriteByte,

-PF_WriteChar,

-PF_WriteShort,

-PF_WriteLong,

-PF_WriteCoord,

-PF_WriteAngle,

-PF_WriteString,

-PF_WriteEntity,

-

-#ifdef QUAKE2

-PF_sin,

-PF_cos,

-PF_sqrt,

-PF_changepitch,

-PF_TraceToss,

-PF_etos,

-PF_WaterMove,

-#else

-PF_Fixme,

-PF_Fixme,

-PF_Fixme,

-PF_Fixme,

-PF_Fixme,

-PF_Fixme,

-PF_Fixme,

-#endif

-

-SV_MoveToGoal,

-PF_precache_file,

-PF_makestatic,

-

-PF_changelevel,

-PF_Fixme,

-

-PF_cvar_set,

-PF_centerprint,

-

-PF_ambientsound,

-

-PF_precache_model,

-PF_precache_sound,		// precache_sound2 is different only for qcc

-PF_precache_file,

-

-PF_setspawnparms

-};

-

-builtin_t *pr_builtins = pr_builtin;

-int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+#define	RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
+
+/*
+===============================================================================
+
+						BUILT-IN FUNCTIONS
+
+===============================================================================
+*/
+
+char *PF_VarString (int	first)
+{
+	int		i;
+	static char out[256];
+	
+	out[0] = 0;
+	for (i=first ; i<pr_argc ; i++)
+	{
+		strcat (out, G_STRING((OFS_PARM0+i*3)));
+	}
+	return out;
+}
+
+
+/*
+=================
+PF_errror
+
+This is a TERMINAL error, which will kill off the entire server.
+Dumps self.
+
+error(value)
+=================
+*/
+void PF_error (void)
+{
+	char	*s;
+	edict_t	*ed;
+	
+	s = PF_VarString(0);
+	Con_Printf ("======SERVER ERROR in %s:\n%s\n"
+	,pr_strings + pr_xfunction->s_name,s);
+	ed = PROG_TO_EDICT(pr_global_struct->self);
+	ED_Print (ed);
+
+	Host_Error ("Program error");
+}
+
+/*
+=================
+PF_objerror
+
+Dumps out self, then an error message.  The program is aborted and self is
+removed, but the level can continue.
+
+objerror(value)
+=================
+*/
+void PF_objerror (void)
+{
+	char	*s;
+	edict_t	*ed;
+	
+	s = PF_VarString(0);
+	Con_Printf ("======OBJECT ERROR in %s:\n%s\n"
+	,pr_strings + pr_xfunction->s_name,s);
+	ed = PROG_TO_EDICT(pr_global_struct->self);
+	ED_Print (ed);
+	ED_Free (ed);
+	
+	Host_Error ("Program error");
+}
+
+
+
+/*
+==============
+PF_makevectors
+
+Writes new values for v_forward, v_up, and v_right based on angles
+makevectors(vector)
+==============
+*/
+void PF_makevectors (void)
+{
+	AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
+}
+
+/*
+=================
+PF_setorigin
+
+This is the only valid way to move an object without using the physics of the world (setting velocity and waiting).  Directly changing origin will not set internal links correctly, so clipping would be messed up.  This should be called when an object is spawned, and then only if it is teleported.
+
+setorigin (entity, origin)
+=================
+*/
+void PF_setorigin (void)
+{
+	edict_t	*e;
+	float	*org;
+	
+	e = G_EDICT(OFS_PARM0);
+	org = G_VECTOR(OFS_PARM1);
+	VectorCopy (org, e->u.v.origin);
+	SV_LinkEdict (e, false);
+}
+
+
+void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
+{
+	float	*angles;
+	vec3_t	rmin, rmax;
+	float	bounds[2][3];
+	float	xvector[2], yvector[2];
+	float	a;
+	vec3_t	base, transformed;
+	int		i, j, k, l;
+	
+	for (i=0 ; i<3 ; i++)
+		if (min[i] > max[i])
+			PR_RunError ("backwards mins/maxs");
+
+	rotate = false;		// FIXME: implement rotation properly again
+
+	if (!rotate)
+	{
+		VectorCopy (min, rmin);
+		VectorCopy (max, rmax);
+	}
+	else
+	{
+	// find min / max for rotations
+		angles = e->u.v.angles;
+		
+		a = angles[1]/180 * M_PI;
+		
+		xvector[0] = cos(a);
+		xvector[1] = sin(a);
+		yvector[0] = -sin(a);
+		yvector[1] = cos(a);
+		
+		VectorCopy (min, bounds[0]);
+		VectorCopy (max, bounds[1]);
+		
+		rmin[0] = rmin[1] = rmin[2] = 9999;
+		rmax[0] = rmax[1] = rmax[2] = -9999;
+		
+		for (i=0 ; i<= 1 ; i++)
+		{
+			base[0] = bounds[i][0];
+			for (j=0 ; j<= 1 ; j++)
+			{
+				base[1] = bounds[j][1];
+				for (k=0 ; k<= 1 ; k++)
+				{
+					base[2] = bounds[k][2];
+					
+				// transform the point
+					transformed[0] = xvector[0]*base[0] + yvector[0]*base[1];
+					transformed[1] = xvector[1]*base[0] + yvector[1]*base[1];
+					transformed[2] = base[2];
+					
+					for (l=0 ; l<3 ; l++)
+					{
+						if (transformed[l] < rmin[l])
+							rmin[l] = transformed[l];
+						if (transformed[l] > rmax[l])
+							rmax[l] = transformed[l];
+					}
+				}
+			}
+		}
+	}
+	
+// set derived values
+	VectorCopy (rmin, e->u.v.mins);
+	VectorCopy (rmax, e->u.v.maxs);
+	VectorSubtract (max, min, e->u.v.size);
+	
+	SV_LinkEdict (e, false);
+}
+
+/*
+=================
+PF_setsize
+
+the size box is rotated by the current angle
+
+setsize (entity, minvector, maxvector)
+=================
+*/
+void PF_setsize (void)
+{
+	edict_t	*e;
+	float	*min, *max;
+	
+	e = G_EDICT(OFS_PARM0);
+	min = G_VECTOR(OFS_PARM1);
+	max = G_VECTOR(OFS_PARM2);
+	SetMinMaxSize (e, min, max, false);
+}
+
+
+/*
+=================
+PF_setmodel
+
+setmodel(entity, model)
+=================
+*/
+void PF_setmodel (void)
+{
+	edict_t	*e;
+	char	*m, **check;
+	model_t	*mod;
+	int		i;
+
+	e = G_EDICT(OFS_PARM0);
+	m = G_STRING(OFS_PARM1);
+
+// check to see if model was properly precached
+	for (i=0, check = sv.model_precache ; *check ; i++, check++)
+		if (!strcmp(*check, m))
+			break;
+			
+	if (!*check)
+		PR_RunError ("no precache: %s\n", m);
+		
+
+	e->u.v.model = m - pr_strings;
+	e->u.v.modelindex = i; //SV_ModelIndex (m);
+
+	mod = sv.models[ (int)e->u.v.modelindex];  // Mod_ForName (m, true);
+	
+	if (mod)
+		SetMinMaxSize (e, mod->mins, mod->maxs, true);
+	else
+		SetMinMaxSize (e, vec3_origin, vec3_origin, true);
+}
+
+/*
+=================
+PF_bprint
+
+broadcast print to everyone on server
+
+bprint(value)
+=================
+*/
+void PF_bprint (void)
+{
+	char		*s;
+
+	s = PF_VarString(0);
+	SV_BroadcastPrintf ("%s", s);
+}
+
+/*
+=================
+PF_sprint
+
+single print to a specific client
+
+sprint(clientent, value)
+=================
+*/
+void PF_sprint (void)
+{
+	char		*s;
+	client_t	*client;
+	int			entnum;
+	
+	entnum = G_EDICTNUM(OFS_PARM0);
+	s = PF_VarString(1);
+	
+	if (entnum < 1 || entnum > svs.maxclients)
+	{
+		Con_Printf ("tried to sprint to a non-client\n");
+		return;
+	}
+		
+	client = &svs.clients[entnum-1];
+		
+	MSG_WriteChar (&client->message,svc_print);
+	MSG_WriteString (&client->message, s );
+}
+
+
+/*
+=================
+PF_centerprint
+
+single print to a specific client
+
+centerprint(clientent, value)
+=================
+*/
+void PF_centerprint (void)
+{
+	char		*s;
+	client_t	*client;
+	int			entnum;
+	
+	entnum = G_EDICTNUM(OFS_PARM0);
+	s = PF_VarString(1);
+	
+	if (entnum < 1 || entnum > svs.maxclients)
+	{
+		Con_Printf ("tried to sprint to a non-client\n");
+		return;
+	}
+		
+	client = &svs.clients[entnum-1];
+		
+	MSG_WriteChar (&client->message,svc_centerprint);
+	MSG_WriteString (&client->message, s );
+}
+
+
+/*
+=================
+PF_normalize
+
+vector normalize(vector)
+=================
+*/
+void PF_normalize (void)
+{
+	float	*value1;
+	vec3_t	newvalue;
+	float	temp;
+	
+	value1 = G_VECTOR(OFS_PARM0);
+
+	temp = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
+	temp = sqrt(temp);
+	
+	if (temp == 0)
+		newvalue[0] = newvalue[1] = newvalue[2] = 0;
+	else
+	{
+		temp = 1/temp;
+		newvalue[0] = value1[0] * temp;
+		newvalue[1] = value1[1] * temp;
+		newvalue[2] = value1[2] * temp;
+	}
+	
+	VectorCopy (newvalue, G_VECTOR(OFS_RETURN));	
+}
+
+/*
+=================
+PF_vlen
+
+scalar vlen(vector)
+=================
+*/
+void PF_vlen (void)
+{
+	float	*value1;
+	float	temp;
+	
+	value1 = G_VECTOR(OFS_PARM0);
+
+	temp = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
+	temp = sqrt(temp);
+	
+	G_FLOAT(OFS_RETURN) = temp;
+}
+
+/*
+=================
+PF_vectoyaw
+
+float vectoyaw(vector)
+=================
+*/
+void PF_vectoyaw (void)
+{
+	float	*value1;
+	float	yaw;
+	
+	value1 = G_VECTOR(OFS_PARM0);
+
+	if (value1[1] == 0 && value1[0] == 0)
+		yaw = 0;
+	else
+	{
+		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
+		if (yaw < 0)
+			yaw += 360;
+	}
+
+	G_FLOAT(OFS_RETURN) = yaw;
+}
+
+
+/*
+=================
+PF_vectoangles
+
+vector vectoangles(vector)
+=================
+*/
+void PF_vectoangles (void)
+{
+	float	*value1;
+	float	forward;
+	float	yaw, pitch;
+	
+	value1 = G_VECTOR(OFS_PARM0);
+
+	if (value1[1] == 0 && value1[0] == 0)
+	{
+		yaw = 0;
+		if (value1[2] > 0)
+			pitch = 90;
+		else
+			pitch = 270;
+	}
+	else
+	{
+		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
+		if (yaw < 0)
+			yaw += 360;
+
+		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
+		pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
+		if (pitch < 0)
+			pitch += 360;
+	}
+
+	G_FLOAT(OFS_RETURN+0) = pitch;
+	G_FLOAT(OFS_RETURN+1) = yaw;
+	G_FLOAT(OFS_RETURN+2) = 0;
+}
+
+/*
+=================
+PF_Random
+
+Returns a number from 0<= num < 1
+
+random()
+=================
+*/
+void PF_random (void)
+{
+	float		num;
+		
+	num = (rand ()&0x7fff) / ((float)0x7fff);
+	
+	G_FLOAT(OFS_RETURN) = num;
+}
+
+/*
+=================
+PF_particle
+
+particle(origin, color, count)
+=================
+*/
+void PF_particle (void)
+{
+	float		*org, *dir;
+	float		color;
+	float		count;
+			
+	org = G_VECTOR(OFS_PARM0);
+	dir = G_VECTOR(OFS_PARM1);
+	color = G_FLOAT(OFS_PARM2);
+	count = G_FLOAT(OFS_PARM3);
+	SV_StartParticle (org, dir, (int) color, (int) count);
+}
+
+
+/*
+=================
+PF_ambientsound
+
+=================
+*/
+void PF_ambientsound (void)
+{
+	char		**check;
+	char		*samp;
+	float		*pos;
+	float 		vol, attenuation;
+	int			i, soundnum;
+
+	pos = G_VECTOR (OFS_PARM0);			
+	samp = G_STRING(OFS_PARM1);
+	vol = G_FLOAT(OFS_PARM2);
+	attenuation = G_FLOAT(OFS_PARM3);
+	
+// check to see if samp was properly precached
+	for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
+		if (!strcmp(*check,samp))
+			break;
+			
+	if (!*check)
+	{
+		Con_Printf ("no precache: %s\n", samp);
+		return;
+	}
+
+// add an svc_spawnambient command to the level signon packet
+
+	MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
+	for (i=0 ; i<3 ; i++)
+		MSG_WriteCoord(&sv.signon, pos[i]);
+
+	MSG_WriteByte (&sv.signon, soundnum);
+
+	MSG_WriteByte (&sv.signon, (int) (vol*255));
+	MSG_WriteByte (&sv.signon, (int) (attenuation*64));
+
+}
+
+/*
+=================
+PF_sound
+
+Each entity can have eight independant sound sources, like voice,
+weapon, feet, etc.
+
+Channel 0 is an auto-allocate channel, the others override anything
+allready running on that entity/channel pair.
+
+An attenuation of 0 will play full volume everywhere in the level.
+Larger attenuations will drop off.
+
+=================
+*/
+void PF_sound (void)
+{
+	char		*sample;
+	int			channel;
+	edict_t		*entity;
+	int 		volume;
+	float attenuation;
+		
+	entity = G_EDICT(OFS_PARM0);
+	channel = (int) G_FLOAT(OFS_PARM1);
+	sample = G_STRING(OFS_PARM2);
+	volume = (int)(G_FLOAT(OFS_PARM3) * 255);
+	attenuation = G_FLOAT(OFS_PARM4);
+	
+	if (volume < 0 || volume > 255)
+		Sys_Error ("SV_StartSound: volume = %i", volume);
+
+	if (attenuation < 0 || attenuation > 4)
+		Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
+
+	if (channel < 0 || channel > 7)
+		Sys_Error ("SV_StartSound: channel = %i", channel);
+
+	SV_StartSound (entity, channel, sample, volume, attenuation);
+}
+
+/*
+=================
+PF_break
+
+break()
+=================
+*/
+void PF_break (void)
+{
+Con_Printf ("break statement\n");
+*(int *)-4 = 0;	// dump to debugger
+//	PR_RunError ("break statement");
+}
+
+/*
+=================
+PF_traceline
+
+Used for use tracing and shot targeting
+Traces are blocked by bbox and exact bsp entityes, and also slide box entities
+if the tryents flag is set.
+
+traceline (vector1, vector2, tryents)
+=================
+*/
+void PF_traceline (void)
+{
+	float	*v1, *v2;
+	trace_t	trace;
+	int		nomonsters;
+	edict_t	*ent;
+
+	v1 = G_VECTOR(OFS_PARM0);
+	v2 = G_VECTOR(OFS_PARM1);
+	nomonsters = (int) G_FLOAT(OFS_PARM2);
+	ent = G_EDICT(OFS_PARM3);
+
+	trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
+
+	pr_global_struct->trace_allsolid = trace.allsolid;
+	pr_global_struct->trace_startsolid = trace.startsolid;
+	pr_global_struct->trace_fraction = trace.fraction;
+	pr_global_struct->trace_inwater = trace.inwater;
+	pr_global_struct->trace_inopen = trace.inopen;
+	VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
+	VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
+	pr_global_struct->trace_plane_dist =  trace.plane.dist;	
+	if (trace.ent)
+		pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
+	else
+		pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
+}
+
+
+#ifdef QUAKE2
+extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
+
+void PF_TraceToss (void)
+{
+	trace_t	trace;
+	edict_t	*ent;
+	edict_t	*ignore;
+
+	ent = G_EDICT(OFS_PARM0);
+	ignore = G_EDICT(OFS_PARM1);
+
+	trace = SV_Trace_Toss (ent, ignore);
+
+	pr_global_struct->trace_allsolid = trace.allsolid;
+	pr_global_struct->trace_startsolid = trace.startsolid;
+	pr_global_struct->trace_fraction = trace.fraction;
+	pr_global_struct->trace_inwater = trace.inwater;
+	pr_global_struct->trace_inopen = trace.inopen;
+	VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
+	VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
+	pr_global_struct->trace_plane_dist =  trace.plane.dist;	
+	if (trace.ent)
+		pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
+	else
+		pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
+}
+#endif
+
+
+/*
+=================
+PF_checkpos
+
+Returns true if the given entity can move to the given position from it's
+current position by walking or rolling.
+FIXME: make work...
+scalar checkpos (entity, vector)
+=================
+*/
+void PF_checkpos (void)
+{
+}
+
+//============================================================================
+
+byte	checkpvs[MAX_MAP_LEAFS/8];
+
+int PF_newcheckclient (int check)
+{
+	int		i;
+	byte	*pvs;
+	edict_t	*ent;
+	mleaf_t	*leaf;
+	vec3_t	org;
+
+// cycle to the next one
+
+	if (check < 1)
+		check = 1;
+	if (check > svs.maxclients)
+		check = svs.maxclients;
+
+	if (check == svs.maxclients)
+		i = 1;
+	else
+		i = check + 1;
+
+	for ( ;  ; i++)
+	{
+		if (i == svs.maxclients+1)
+			i = 1;
+
+		ent = EDICT_NUM(i);
+
+		if (i == check)
+			break;	// didn't find anything else
+
+		if (ent->free)
+			continue;
+		if (ent->u.v.health <= 0)
+			continue;
+		if ((int)ent->u.v.flags & FL_NOTARGET)
+			continue;
+
+	// anything that is a client, or has a client as an enemy
+		break;
+	}
+
+// get the PVS for the entity
+	VectorAdd (ent->u.v.origin, ent->u.v.view_ofs, org);
+	leaf = Mod_PointInLeaf (org, sv.worldmodel);
+	pvs = Mod_LeafPVS (leaf, sv.worldmodel);
+	memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
+
+	return i;
+}
+
+/*
+=================
+PF_checkclient
+
+Returns a client (or object that has a client enemy) that would be a
+valid target.
+
+If there are more than one valid options, they are cycled each frame
+
+If (self.origin + self.viewofs) is not in the PVS of the current target,
+it is not returned at all.
+
+name checkclient ()
+=================
+*/
+#define	MAX_CHECK	16
+int c_invis, c_notvis;
+void PF_checkclient (void)
+{
+	edict_t	*ent, *self;
+	mleaf_t	*leaf;
+	int		l;
+	vec3_t	view;
+	
+// find a new check if on a new frame
+	if (sv.time - sv.lastchecktime >= 0.1)
+	{
+		sv.lastcheck = PF_newcheckclient (sv.lastcheck);
+		sv.lastchecktime = sv.time;
+	}
+
+// return check if it might be visible	
+	ent = EDICT_NUM(sv.lastcheck);
+	if (ent->free || ent->u.v.health <= 0)
+	{
+		RETURN_EDICT(sv.edicts);
+		return;
+	}
+
+// if current entity can't possibly see the check entity, return 0
+	self = PROG_TO_EDICT(pr_global_struct->self);
+	VectorAdd (self->u.v.origin, self->u.v.view_ofs, view);
+	leaf = Mod_PointInLeaf (view, sv.worldmodel);
+	l = (leaf - sv.worldmodel->leafs) - 1;
+	if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
+	{
+c_notvis++;
+		RETURN_EDICT(sv.edicts);
+		return;
+	}
+
+// might be able to see it
+c_invis++;
+	RETURN_EDICT(ent);
+}
+
+//============================================================================
+
+
+/*
+=================
+PF_stuffcmd
+
+Sends text over to the client's execution buffer
+
+stuffcmd (clientent, value)
+=================
+*/
+void PF_stuffcmd (void)
+{
+	int		entnum;
+	char	*str;
+	client_t	*old;
+	
+	entnum = G_EDICTNUM(OFS_PARM0);
+	if (entnum < 1 || entnum > svs.maxclients)
+		PR_RunError ("Parm 0 not a client");
+	str = G_STRING(OFS_PARM1);	
+	
+	old = host_client;
+	host_client = &svs.clients[entnum-1];
+	Host_ClientCommands ("%s", str);
+	host_client = old;
+}
+
+/*
+=================
+PF_localcmd
+
+Sends text over to the client's execution buffer
+
+localcmd (string)
+=================
+*/
+void PF_localcmd (void)
+{
+	char	*str;
+	
+	str = G_STRING(OFS_PARM0);	
+	Cbuf_AddText (str);
+}
+
+/*
+=================
+PF_cvar
+
+float cvar (string)
+=================
+*/
+void PF_cvar (void)
+{
+	char	*str;
+	
+	str = G_STRING(OFS_PARM0);
+	
+	G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
+}
+
+/*
+=================
+PF_cvar_set
+
+float cvar (string)
+=================
+*/
+void PF_cvar_set (void)
+{
+	char	*var, *val;
+	
+	var = G_STRING(OFS_PARM0);
+	val = G_STRING(OFS_PARM1);
+	
+	Cvar_Set (var, val);
+}
+
+/*
+=================
+PF_findradius
+
+Returns a chain of entities that have origins within a spherical area
+
+findradius (origin, radius)
+=================
+*/
+void PF_findradius (void)
+{
+	edict_t	*ent, *chain;
+	float	rad;
+	float	*org;
+	vec3_t	eorg;
+	int		i, j;
+
+	chain = (edict_t *)sv.edicts;
+	
+	org = G_VECTOR(OFS_PARM0);
+	rad = G_FLOAT(OFS_PARM1);
+
+	ent = NEXT_EDICT(sv.edicts);
+	for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
+	{
+		if (ent->free)
+			continue;
+		if (ent->u.v.solid == SOLID_NOT)
+			continue;
+		for (j=0 ; j<3 ; j++)
+			eorg[j] = org[j] - (ent->u.v.origin[j] + (ent->u.v.mins[j] + ent->u.v.maxs[j])*0.5);			
+		if (Length(eorg) > rad)
+			continue;
+			
+		ent->u.v.chain = EDICT_TO_PROG(chain);
+		chain = ent;
+	}
+
+	RETURN_EDICT(chain);
+}
+
+
+/*
+=========
+PF_dprint
+=========
+*/
+void PF_dprint (void)
+{
+	Con_DPrintf ("%s",PF_VarString(0));
+}
+
+char	pr_string_temp[128];
+
+void PF_ftos (void)
+{
+	float	v;
+	v = G_FLOAT(OFS_PARM0);
+	
+	if (v == (int)v)
+		sprintf (pr_string_temp, "%d",(int)v);
+	else
+		sprintf (pr_string_temp, "%5.1f",v);
+	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
+}
+
+void PF_fabs (void)
+{
+	float	v;
+	v = G_FLOAT(OFS_PARM0);
+	G_FLOAT(OFS_RETURN) = fabs(v);
+}
+
+void PF_vtos (void)
+{
+	sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
+	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
+}
+
+#ifdef QUAKE2
+void PF_etos (void)
+{
+	sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0));
+	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
+}
+#endif
+
+void PF_Spawn (void)
+{
+	edict_t	*ed;
+	ed = ED_Alloc();
+	RETURN_EDICT(ed);
+}
+
+void PF_Remove (void)
+{
+	edict_t	*ed;
+	
+	ed = G_EDICT(OFS_PARM0);
+	ED_Free (ed);
+}
+
+
+// entity (entity start, .string field, string match) find = #5;
+void PF_Find (void)
+#ifdef QUAKE2
+{
+	int		e;	
+	int		f;
+	char	*s, *t;
+	edict_t	*ed;
+	edict_t	*first;
+	edict_t	*second;
+	edict_t	*last;
+
+	first = second = last = (edict_t *)sv.edicts;
+	e = G_EDICTNUM(OFS_PARM0);
+	f = G_INT(OFS_PARM1);
+	s = G_STRING(OFS_PARM2);
+	if (!s)
+		PR_RunError ("PF_Find: bad search string");
+		
+	for (e++ ; e < sv.num_edicts ; e++)
+	{
+		ed = EDICT_NUM(e);
+		if (ed->free)
+			continue;
+		t = E_STRING(ed,f);
+		if (!t)
+			continue;
+		if (!strcmp(t,s))
+		{
+			if (first == (edict_t *)sv.edicts)
+				first = ed;
+			else if (second == (edict_t *)sv.edicts)
+				second = ed;
+			ed->u.v.chain = EDICT_TO_PROG(last);
+			last = ed;
+		}
+	}
+
+	if (first != last)
+	{
+		if (last != second)
+			first->u.v.chain = last->u.v.chain;
+		else
+			first->u.v.chain = EDICT_TO_PROG(last);
+		last->u.v.chain = EDICT_TO_PROG((edict_t *)sv.edicts);
+		if (second && second != last)
+			second->u.v.chain = EDICT_TO_PROG(last);
+	}
+	RETURN_EDICT(first);
+}
+#else
+{
+	int		e;	
+	int		f;
+	char	*s, *t;
+	edict_t	*ed;
+
+	e = G_EDICTNUM(OFS_PARM0);
+	f = G_INT(OFS_PARM1);
+	s = G_STRING(OFS_PARM2);
+	if (!s)
+		PR_RunError ("PF_Find: bad search string");
+		
+	for (e++ ; e < sv.num_edicts ; e++)
+	{
+		ed = EDICT_NUM(e);
+		if (ed->free)
+			continue;
+		t = E_STRING(ed,f);
+		if (!t)
+			continue;
+		if (!strcmp(t,s))
+		{
+			RETURN_EDICT(ed);
+			return;
+		}
+	}
+
+	RETURN_EDICT(sv.edicts);
+}
+#endif
+
+void PR_CheckEmptyString (char *s)
+{
+	if (s[0] <= ' ')
+		PR_RunError ("Bad string");
+}
+
+void PF_precache_file (void)
+{	// precache_file is only used to copy files with qcc, it does nothing
+	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
+}
+
+void PF_precache_sound (void)
+{
+	char	*s;
+	int		i;
+	
+	if (sv.state != ss_loading)
+		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
+		
+	s = G_STRING(OFS_PARM0);
+	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
+	PR_CheckEmptyString (s);
+	
+	for (i=0 ; i<MAX_SOUNDS ; i++)
+	{
+		if (!sv.sound_precache[i])
+		{
+			sv.sound_precache[i] = s;
+			return;
+		}
+		if (!strcmp(sv.sound_precache[i], s))
+			return;
+	}
+	PR_RunError ("PF_precache_sound: overflow");
+}
+
+void PF_precache_model (void)
+{
+	char	*s;
+	int		i;
+	
+	if (sv.state != ss_loading)
+		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
+		
+	s = G_STRING(OFS_PARM0);
+	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
+	PR_CheckEmptyString (s);
+
+	for (i=0 ; i<MAX_MODELS ; i++)
+	{
+		if (!sv.model_precache[i])
+		{
+			sv.model_precache[i] = s;
+			sv.models[i] = Mod_ForName (s, true);
+			return;
+		}
+		if (!strcmp(sv.model_precache[i], s))
+			return;
+	}
+	PR_RunError ("PF_precache_model: overflow");
+}
+
+
+void PF_coredump (void)
+{
+	ED_PrintEdicts ();
+}
+
+void PF_traceon (void)
+{
+	pr_trace = true;
+}
+
+void PF_traceoff (void)
+{
+	pr_trace = false;
+}
+
+void PF_eprint (void)
+{
+	ED_PrintNum (G_EDICTNUM(OFS_PARM0));
+}
+
+/*
+===============
+PF_walkmove
+
+float(float yaw, float dist) walkmove
+===============
+*/
+void PF_walkmove (void)
+{
+	edict_t	*ent;
+	float	yaw, dist;
+	vec3_t	move;
+	dfunction_t	*oldf;
+	int 	oldself;
+	
+	ent = PROG_TO_EDICT(pr_global_struct->self);
+	yaw = G_FLOAT(OFS_PARM0);
+	dist = G_FLOAT(OFS_PARM1);
+	
+	if ( !( (int)ent->u.v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+	{
+		G_FLOAT(OFS_RETURN) = 0;
+		return;
+	}
+
+	yaw = yaw*M_PI*2 / 360;
+	
+	move[0] = cos(yaw)*dist;
+	move[1] = sin(yaw)*dist;
+	move[2] = 0;
+
+// save program state, because SV_movestep may call other progs
+	oldf = pr_xfunction;
+	oldself = pr_global_struct->self;
+	
+	G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
+	
+	
+// restore program state
+	pr_xfunction = oldf;
+	pr_global_struct->self = oldself;
+}
+
+/*
+===============
+PF_droptofloor
+
+void() droptofloor
+===============
+*/
+void PF_droptofloor (void)
+{
+	edict_t		*ent;
+	vec3_t		end;
+	trace_t		trace;
+	
+	ent = PROG_TO_EDICT(pr_global_struct->self);
+
+	VectorCopy (ent->u.v.origin, end);
+	end[2] -= 256;
+	
+	trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
+
+	if (trace.fraction == 1 || trace.allsolid)
+		G_FLOAT(OFS_RETURN) = 0;
+	else
+	{
+		VectorCopy (trace.endpos, ent->u.v.origin);
+		SV_LinkEdict (ent, false);
+		ent->u.v.flags = (int)ent->u.v.flags | FL_ONGROUND;
+		ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
+		G_FLOAT(OFS_RETURN) = 1;
+	}
+}
+
+/*
+===============
+PF_lightstyle
+
+void(float style, string value) lightstyle
+===============
+*/
+void PF_lightstyle (void)
+{
+	int		style;
+	char	*val;
+	client_t	*client;
+	int			j;
+	
+	style = (int) G_FLOAT(OFS_PARM0);
+	val = G_STRING(OFS_PARM1);
+
+// change the string in sv
+	sv.lightstyles[style] = val;
+	
+// send message to all clients on this server
+	if (sv.state != ss_active)
+		return;
+	
+	for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
+		if (client->active || client->spawned)
+		{
+			MSG_WriteChar (&client->message, svc_lightstyle);
+			MSG_WriteChar (&client->message,style);
+			MSG_WriteString (&client->message, val);
+		}
+}
+
+void PF_rint (void)
+{
+	float	f;
+	f = G_FLOAT(OFS_PARM0);
+	if (f > 0)
+		G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
+	else
+		G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
+}
+void PF_floor (void)
+{
+	G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
+}
+void PF_ceil (void)
+{
+	G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
+}
+
+
+/*
+=============
+PF_checkbottom
+=============
+*/
+void PF_checkbottom (void)
+{
+	edict_t	*ent;
+	
+	ent = G_EDICT(OFS_PARM0);
+
+	G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);
+}
+
+/*
+=============
+PF_pointcontents
+=============
+*/
+void PF_pointcontents (void)
+{
+	float	*v;
+	
+	v = G_VECTOR(OFS_PARM0);
+
+	G_FLOAT(OFS_RETURN) = SV_PointContents (v);	
+}
+
+/*
+=============
+PF_nextent
+
+entity nextent(entity)
+=============
+*/
+void PF_nextent (void)
+{
+	int		i;
+	edict_t	*ent;
+	
+	i = G_EDICTNUM(OFS_PARM0);
+	while (1)
+	{
+		i++;
+		if (i == sv.num_edicts)
+		{
+			RETURN_EDICT(sv.edicts);
+			return;
+		}
+		ent = EDICT_NUM(i);
+		if (!ent->free)
+		{
+			RETURN_EDICT(ent);
+			return;
+		}
+	}
+}
+
+/*
+=============
+PF_aim
+
+Pick a vector for the player to shoot along
+vector aim(entity, missilespeed)
+=============
+*/
+cvar_t	sv_aim = CVAR2("sv_aim", "0.93");
+void PF_aim (void)
+{
+	edict_t	*ent, *check, *bestent;
+	vec3_t	start, dir, end, bestdir;
+	int		i, j;
+	trace_t	tr;
+	float	dist, bestdist;
+	float	speed;
+	
+	ent = G_EDICT(OFS_PARM0);
+	speed = G_FLOAT(OFS_PARM1);
+
+	VectorCopy (ent->u.v.origin, start);
+	start[2] += 20;
+
+// try sending a trace straight
+	VectorCopy (pr_global_struct->v_forward, dir);
+	VectorMA (start, 2048, dir, end);
+	tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
+	if (tr.ent && tr.ent->u.v.takedamage == DAMAGE_AIM
+	&& (!teamplay.value || ent->u.v.team <=0 || ent->u.v.team != tr.ent->u.v.team) )
+	{
+		VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
+		return;
+	}
+
+
+// try all possible entities
+	VectorCopy (dir, bestdir);
+	bestdist = sv_aim.value;
+	bestent = NULL;
+	
+	check = NEXT_EDICT(sv.edicts);
+	for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
+	{
+		if (check->u.v.takedamage != DAMAGE_AIM)
+			continue;
+		if (check == ent)
+			continue;
+		if (teamplay.value && ent->u.v.team > 0 && ent->u.v.team == check->u.v.team)
+			continue;	// don't aim at teammate
+		for (j=0 ; j<3 ; j++)
+			end[j] = check->u.v.origin[j]
+			+ 0.5*(check->u.v.mins[j] + check->u.v.maxs[j]);
+		VectorSubtract (end, start, dir);
+		VectorNormalize (dir);
+		dist = DotProduct (dir, pr_global_struct->v_forward);
+		if (dist < bestdist)
+			continue;	// to far to turn
+		tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
+		if (tr.ent == check)
+		{	// can shoot at this one
+			bestdist = dist;
+			bestent = check;
+		}
+	}
+	
+	if (bestent)
+	{
+		VectorSubtract (bestent->u.v.origin, ent->u.v.origin, dir);
+		dist = DotProduct (dir, pr_global_struct->v_forward);
+		VectorScale (pr_global_struct->v_forward, dist, end);
+		end[2] = dir[2];
+		VectorNormalize (end);
+		VectorCopy (end, G_VECTOR(OFS_RETURN));	
+	}
+	else
+	{
+		VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
+	}
+}
+
+/*
+==============
+PF_changeyaw
+
+This was a major timewaster in progs, so it was converted to C
+==============
+*/
+void PF_changeyaw (void)
+{
+	edict_t		*ent;
+	float		ideal, current, move, speed;
+	
+	ent = PROG_TO_EDICT(pr_global_struct->self);
+	current = anglemod( ent->u.v.angles[1] );
+	ideal = ent->u.v.ideal_yaw;
+	speed = ent->u.v.yaw_speed;
+	
+	if (current == ideal)
+		return;
+	move = ideal - current;
+	if (ideal > current)
+	{
+		if (move >= 180)
+			move = move - 360;
+	}
+	else
+	{
+		if (move <= -180)
+			move = move + 360;
+	}
+	if (move > 0)
+	{
+		if (move > speed)
+			move = speed;
+	}
+	else
+	{
+		if (move < -speed)
+			move = -speed;
+	}
+	
+	ent->u.v.angles[1] = anglemod (current + move);
+}
+
+#ifdef QUAKE2
+/*
+==============
+PF_changepitch
+==============
+*/
+void PF_changepitch (void)
+{
+	edict_t		*ent;
+	float		ideal, current, move, speed;
+	
+	ent = G_EDICT(OFS_PARM0);
+	current = anglemod( ent->u.v.angles[0] );
+	ideal = ent->u.v.idealpitch;
+	speed = ent->u.v.pitch_speed;
+	
+	if (current == ideal)
+		return;
+	move = ideal - current;
+	if (ideal > current)
+	{
+		if (move >= 180)
+			move = move - 360;
+	}
+	else
+	{
+		if (move <= -180)
+			move = move + 360;
+	}
+	if (move > 0)
+	{
+		if (move > speed)
+			move = speed;
+	}
+	else
+	{
+		if (move < -speed)
+			move = -speed;
+	}
+	
+	ent->u.v.angles[0] = anglemod (current + move);
+}
+#endif
+
+/*
+===============================================================================
+
+MESSAGE WRITING
+
+===============================================================================
+*/
+
+#define	MSG_BROADCAST	0		// unreliable to all
+#define	MSG_ONE			1		// reliable to one (msg_entity)
+#define	MSG_ALL			2		// reliable to all
+#define	MSG_INIT		3		// write to the init string
+
+sizebuf_t *WriteDest (void)
+{
+	int		entnum;
+	int		dest;
+	edict_t	*ent;
+
+	dest = (int) G_FLOAT(OFS_PARM0);
+	switch (dest)
+	{
+	case MSG_BROADCAST:
+		return &sv.datagram;
+	
+	case MSG_ONE:
+		ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
+		entnum = NUM_FOR_EDICT(ent);
+		if (entnum < 1 || entnum > svs.maxclients)
+			PR_RunError ("WriteDest: not a client");
+		return &svs.clients[entnum-1].message;
+		
+	case MSG_ALL:
+		return &sv.reliable_datagram;
+	
+	case MSG_INIT:
+		return &sv.signon;
+
+	default:
+		PR_RunError ("WriteDest: bad destination");
+		break;
+	}
+	
+	return NULL;
+}
+
+void PF_WriteByte (void)
+{
+	MSG_WriteByte (WriteDest(), (int) G_FLOAT(OFS_PARM1));
+}
+
+void PF_WriteChar (void)
+{
+	MSG_WriteChar (WriteDest(), (int) G_FLOAT(OFS_PARM1));
+}
+
+void PF_WriteShort (void)
+{
+	MSG_WriteShort (WriteDest(), (int) G_FLOAT(OFS_PARM1));
+}
+
+void PF_WriteLong (void)
+{
+	MSG_WriteLong (WriteDest(), (int) G_FLOAT(OFS_PARM1));
+}
+
+void PF_WriteAngle (void)
+{
+	MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
+}
+
+void PF_WriteCoord (void)
+{
+	MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
+}
+
+void PF_WriteString (void)
+{
+	MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
+}
+
+
+void PF_WriteEntity (void)
+{
+	MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
+}
+
+//=============================================================================
+
+int SV_ModelIndex (const char *name);
+
+void PF_makestatic (void)
+{
+	edict_t	*ent;
+	int		i;
+	
+	ent = G_EDICT(OFS_PARM0);
+
+	MSG_WriteByte (&sv.signon,svc_spawnstatic);
+
+	MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->u.v.model));
+
+	MSG_WriteByte (&sv.signon, (int) ent->u.v.frame);
+	MSG_WriteByte (&sv.signon, (int) ent->u.v.colormap);
+	MSG_WriteByte (&sv.signon, (int) ent->u.v.skin);
+	for (i=0 ; i<3 ; i++)
+	{
+		MSG_WriteCoord(&sv.signon, ent->u.v.origin[i]);
+		MSG_WriteAngle(&sv.signon, ent->u.v.angles[i]);
+	}
+
+// throw the entity away now
+	ED_Free (ent);
+}
+
+//=============================================================================
+
+/*
+==============
+PF_setspawnparms
+==============
+*/
+void PF_setspawnparms (void)
+{
+	edict_t	*ent;
+	int		i;
+	client_t	*client;
+
+	ent = G_EDICT(OFS_PARM0);
+	i = NUM_FOR_EDICT(ent);
+	if (i < 1 || i > svs.maxclients)
+		PR_RunError ("Entity is not a client");
+
+	// copy spawn parms out of the client_t
+	client = svs.clients + (i-1);
+
+	for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
+		(&pr_global_struct->parm1)[i] = client->spawn_parms[i];
+}
+
+/*
+==============
+PF_changelevel
+==============
+*/
+void PF_changelevel (void)
+{
+#ifdef QUAKE2
+	char	*s1, *s2;
+
+	if (svs.changelevel_issued)
+		return;
+	svs.changelevel_issued = true;
+
+	s1 = G_STRING(OFS_PARM0);
+	s2 = G_STRING(OFS_PARM1);
+
+	if ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE))
+		Cbuf_AddText (va("changelevel %s %s\n",s1, s2));
+	else
+		Cbuf_AddText (va("changelevel2 %s %s\n",s1, s2));
+#else
+	char	*s;
+
+// make sure we don't issue two changelevels
+	if (svs.changelevel_issued)
+		return;
+	svs.changelevel_issued = true;
+	
+	s = G_STRING(OFS_PARM0);
+	Cbuf_AddText (va("changelevel %s\n",s));
+#endif
+}
+
+
+#ifdef QUAKE2
+
+#define	CONTENT_WATER	-3
+#define CONTENT_SLIME	-4
+#define CONTENT_LAVA	-5
+
+#define FL_IMMUNE_WATER	131072
+#define	FL_IMMUNE_SLIME	262144
+#define FL_IMMUNE_LAVA	524288
+
+#define	CHAN_VOICE	2
+#define	CHAN_BODY	4
+
+#define	ATTN_NORM	1
+
+void PF_WaterMove (void)
+{
+	edict_t		*self;
+	int			flags;
+	int			waterlevel;
+	int			watertype;
+	float		drownlevel;
+	float		damage = 0.0;
+
+	self = PROG_TO_EDICT(pr_global_struct->self);
+
+	if (self->u.v.movetype == MOVETYPE_NOCLIP)
+	{
+		self->u.v.air_finished = sv.time + 12;
+		G_FLOAT(OFS_RETURN) = damage;
+		return;
+	}
+
+	if (self->u.v.health < 0)
+	{
+		G_FLOAT(OFS_RETURN) = damage;
+		return;
+	}
+
+	if (self->u.v.deadflag == DEAD_NO)
+		drownlevel = 3;
+	else
+		drownlevel = 1;
+
+	flags = (int)self->u.v.flags;
+	waterlevel = (int)self->u.v.waterlevel;
+	watertype = (int)self->u.v.watertype;
+
+	if (!(flags & (FL_IMMUNE_WATER + FL_GODMODE)))
+		if (((flags & FL_SWIM) && (waterlevel < drownlevel)) || (waterlevel >= drownlevel))
+		{
+			if (self->u.v.air_finished < sv.time)
+				if (self->u.v.pain_finished < sv.time)
+				{
+					self->u.v.dmg = self->u.v.dmg + 2;
+					if (self->u.v.dmg > 15)
+						self->u.v.dmg = 10;
+//					T_Damage (self, world, world, self.dmg, 0, FALSE);
+					damage = self->u.v.dmg;
+					self->u.v.pain_finished = sv.time + 1.0;
+				}
+		}
+		else
+		{
+			if (self->u.v.air_finished < sv.time)
+//				sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
+				SV_StartSound (self, CHAN_VOICE, "player/gasp2.wav", 255, ATTN_NORM);
+			else if (self->u.v.air_finished < sv.time + 9)
+//				sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
+				SV_StartSound (self, CHAN_VOICE, "player/gasp1.wav", 255, ATTN_NORM);
+			self->u.v.air_finished = sv.time + 12.0;
+			self->u.v.dmg = 2;
+		}
+	
+	if (!waterlevel)
+	{
+		if (flags & FL_INWATER)
+		{	
+			// play leave water sound
+//			sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
+			SV_StartSound (self, CHAN_BODY, "misc/outwater.wav", 255, ATTN_NORM);
+			self->u.v.flags = (float)(flags &~FL_INWATER);
+		}
+		self->u.v.air_finished = sv.time + 12.0;
+		G_FLOAT(OFS_RETURN) = damage;
+		return;
+	}
+
+	if (watertype == CONTENT_LAVA)
+	{	// do damage
+		if (!(flags & (FL_IMMUNE_LAVA + FL_GODMODE)))
+			if (self->u.v.dmgtime < sv.time)
+			{
+				if (self->u.v.radsuit_finished < sv.time)
+					self->u.v.dmgtime = sv.time + 0.2;
+				else
+					self->u.v.dmgtime = sv.time + 1.0;
+//				T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE);
+				damage = (float)(10*waterlevel);
+			}
+	}
+	else if (watertype == CONTENT_SLIME)
+	{	// do damage
+		if (!(flags & (FL_IMMUNE_SLIME + FL_GODMODE)))
+			if (self->u.v.dmgtime < sv.time && self->u.v.radsuit_finished < sv.time)
+			{
+				self->u.v.dmgtime = sv.time + 1.0;
+//				T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE);
+				damage = (float)(4*waterlevel);
+			}
+	}
+	
+	if ( !(flags & FL_INWATER) )
+	{	
+
+// player enter water sound
+		if (watertype == CONTENT_LAVA)
+//			sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
+			SV_StartSound (self, CHAN_BODY, "player/inlava.wav", 255, ATTN_NORM);
+		if (watertype == CONTENT_WATER)
+//			sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
+			SV_StartSound (self, CHAN_BODY, "player/inh2o.wav", 255, ATTN_NORM);
+		if (watertype == CONTENT_SLIME)
+//			sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
+			SV_StartSound (self, CHAN_BODY, "player/slimbrn2.wav", 255, ATTN_NORM);
+
+		self->u.v.flags = (float)(flags | FL_INWATER);
+		self->u.v.dmgtime = 0;
+	}
+	
+	if (! (flags & FL_WATERJUMP) )
+	{
+//		self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
+		VectorMA (self->u.v.velocity, -0.8 * self->u.v.waterlevel * host_frametime, self->u.v.velocity, self->u.v.velocity);
+	}
+
+	G_FLOAT(OFS_RETURN) = damage;
+}
+
+
+void PF_sin (void)
+{
+	G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
+}
+
+void PF_cos (void)
+{
+	G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
+}
+
+void PF_sqrt (void)
+{
+	G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
+}
+#endif
+
+void PF_Fixme (void)
+{
+	PR_RunError ("unimplemented bulitin");
+}
+
+
+
+builtin_t pr_builtin[] =
+{
+PF_Fixme,
+PF_makevectors,	// void(entity e)	makevectors 		= #1;
+PF_setorigin,	// void(entity e, vector o) setorigin	= #2;
+PF_setmodel,	// void(entity e, string m) setmodel	= #3;
+PF_setsize,	// void(entity e, vector min, vector max) setsize = #4;
+PF_Fixme,	// void(entity e, vector min, vector max) setabssize = #5;
+PF_break,	// void() break						= #6;
+PF_random,	// float() random						= #7;
+PF_sound,	// void(entity e, float chan, string samp) sound = #8;
+PF_normalize,	// vector(vector v) normalize			= #9;
+PF_error,	// void(string e) error				= #10;
+PF_objerror,	// void(string e) objerror				= #11;
+PF_vlen,	// float(vector v) vlen				= #12;
+PF_vectoyaw,	// float(vector v) vectoyaw		= #13;
+PF_Spawn,	// entity() spawn						= #14;
+PF_Remove,	// void(entity e) remove				= #15;
+PF_traceline,	// float(vector v1, vector v2, float tryents) traceline = #16;
+PF_checkclient,	// entity() clientlist					= #17;
+PF_Find,	// entity(entity start, .string fld, string match) find = #18;
+PF_precache_sound,	// void(string s) precache_sound		= #19;
+PF_precache_model,	// void(string s) precache_model		= #20;
+PF_stuffcmd,	// void(entity client, string s)stuffcmd = #21;
+PF_findradius,	// entity(vector org, float rad) findradius = #22;
+PF_bprint,	// void(string s) bprint				= #23;
+PF_sprint,	// void(entity client, string s) sprint = #24;
+PF_dprint,	// void(string s) dprint				= #25;
+PF_ftos,	// void(string s) ftos				= #26;
+PF_vtos,	// void(string s) vtos				= #27;
+PF_coredump,
+PF_traceon,
+PF_traceoff,
+PF_eprint,	// void(entity e) debug print an entire entity
+PF_walkmove, // float(float yaw, float dist) walkmove
+PF_Fixme, // float(float yaw, float dist) walkmove
+PF_droptofloor,
+PF_lightstyle,
+PF_rint,
+PF_floor,
+PF_ceil,
+PF_Fixme,
+PF_checkbottom,
+PF_pointcontents,
+PF_Fixme,
+PF_fabs,
+PF_aim,
+PF_cvar,
+PF_localcmd,
+PF_nextent,
+PF_particle,
+PF_changeyaw,
+PF_Fixme,
+PF_vectoangles,
+
+PF_WriteByte,
+PF_WriteChar,
+PF_WriteShort,
+PF_WriteLong,
+PF_WriteCoord,
+PF_WriteAngle,
+PF_WriteString,
+PF_WriteEntity,
+
+#ifdef QUAKE2
+PF_sin,
+PF_cos,
+PF_sqrt,
+PF_changepitch,
+PF_TraceToss,
+PF_etos,
+PF_WaterMove,
+#else
+PF_Fixme,
+PF_Fixme,
+PF_Fixme,
+PF_Fixme,
+PF_Fixme,
+PF_Fixme,
+PF_Fixme,
+#endif
+
+SV_MoveToGoal,
+PF_precache_file,
+PF_makestatic,
+
+PF_changelevel,
+PF_Fixme,
+
+PF_cvar_set,
+PF_centerprint,
+
+PF_ambientsound,
+
+PF_precache_model,
+PF_precache_sound,		// precache_sound2 is different only for qcc
+PF_precache_file,
+
+PF_setspawnparms
+};
+
+builtin_t *pr_builtins = pr_builtin;
+int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
+
diff --git a/quake/src/WinQuake/pr_comp.h b/quake/src/WinQuake/pr_comp.h
index fb09251..4b143cb 100644
--- a/quake/src/WinQuake/pr_comp.h
+++ b/quake/src/WinQuake/pr_comp.h
@@ -23,7 +23,8 @@
 typedef int	func_t;

 typedef int	string_t;

 

-typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer} etype_t;

+typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer,

+  etype_t_max = 1 << 30} etype_t;

 

 

 #define	OFS_NULL		0

diff --git a/quake/src/WinQuake/pr_edict.c b/quake/src/WinQuake/pr_edict.cpp
old mode 100644
new mode 100755
similarity index 89%
rename from quake/src/WinQuake/pr_edict.c
rename to quake/src/WinQuake/pr_edict.cpp
index a884b60..e688d12
--- a/quake/src/WinQuake/pr_edict.c
+++ b/quake/src/WinQuake/pr_edict.cpp
@@ -1,1106 +1,1106 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// sv_edict.c -- entity dictionary

-

-#include "quakedef.h"

-

-dprograms_t		*progs;

-dfunction_t		*pr_functions;

-char			*pr_strings;

-ddef_t			*pr_fielddefs;

-ddef_t			*pr_globaldefs;

-dstatement_t	*pr_statements;

-globalvars_t	*pr_global_struct;

-float			*pr_globals;			// same as pr_global_struct

-int				pr_edict_size;	// in bytes

-

-unsigned short		pr_crc;

-

-int		type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};

-

-ddef_t *ED_FieldAtOfs (int ofs);

-qboolean	ED_ParseEpair (void *base, ddef_t *key, char *s);

-

-cvar_t	nomonsters = {"nomonsters", "0"};

-cvar_t	gamecfg = {"gamecfg", "0"};

-cvar_t	scratch1 = {"scratch1", "0"};

-cvar_t	scratch2 = {"scratch2", "0"};

-cvar_t	scratch3 = {"scratch3", "0"};

-cvar_t	scratch4 = {"scratch4", "0"};

-cvar_t	savedgamecfg = {"savedgamecfg", "0", true};

-cvar_t	saved1 = {"saved1", "0", true};

-cvar_t	saved2 = {"saved2", "0", true};

-cvar_t	saved3 = {"saved3", "0", true};

-cvar_t	saved4 = {"saved4", "0", true};

-

-#define	MAX_FIELD_LEN	64

-#define GEFV_CACHESIZE	2

-

-typedef struct {

-	ddef_t	*pcache;

-	char	field[MAX_FIELD_LEN];

-} gefv_cache;

-

-static gefv_cache	gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}};

-

-/*

-=================

-ED_ClearEdict

-

-Sets everything to NULL

-=================

-*/

-void ED_ClearEdict (edict_t *e)

-{

-	memset (&e->v, 0, progs->entityfields * 4);

-	e->free = false;

-}

-

-/*

-=================

-ED_Alloc

-

-Either finds a free edict, or allocates a new one.

-Try to avoid reusing an entity that was recently freed, because it

-can cause the client to think the entity morphed into something else

-instead of being removed and recreated, which can cause interpolated

-angles and bad trails.

-=================

-*/

-edict_t *ED_Alloc (void)

-{

-	int			i;

-	edict_t		*e;

-

-	for ( i=svs.maxclients+1 ; i<sv.num_edicts ; i++)

-	{

-		e = EDICT_NUM(i);

-		// the first couple seconds of server time can involve a lot of

-		// freeing and allocating, so relax the replacement policy

-		if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )

-		{

-			ED_ClearEdict (e);

-			return e;

-		}

-	}

-	

-	if (i == MAX_EDICTS)

-		Sys_Error ("ED_Alloc: no free edicts");

-		

-	sv.num_edicts++;

-	e = EDICT_NUM(i);

-	ED_ClearEdict (e);

-

-	return e;

-}

-

-/*

-=================

-ED_Free

-

-Marks the edict as free

-FIXME: walk all entities and NULL out references to this entity

-=================

-*/

-void ED_Free (edict_t *ed)

-{

-	SV_UnlinkEdict (ed);		// unlink from world bsp

-

-	ed->free = true;

-	ed->v.model = 0;

-	ed->v.takedamage = 0;

-	ed->v.modelindex = 0;

-	ed->v.colormap = 0;

-	ed->v.skin = 0;

-	ed->v.frame = 0;

-	VectorCopy (vec3_origin, ed->v.origin);

-	VectorCopy (vec3_origin, ed->v.angles);

-	ed->v.nextthink = -1;

-	ed->v.solid = 0;

-	

-	ed->freetime = sv.time;

-}

-

-//===========================================================================

-

-/*

-============

-ED_GlobalAtOfs

-============

-*/

-ddef_t *ED_GlobalAtOfs (int ofs)

-{

-	ddef_t		*def;

-	int			i;

-	

-	for (i=0 ; i<progs->numglobaldefs ; i++)

-	{

-		def = &pr_globaldefs[i];

-		if (def->ofs == ofs)

-			return def;

-	}

-	return NULL;

-}

-

-/*

-============

-ED_FieldAtOfs

-============

-*/

-ddef_t *ED_FieldAtOfs (int ofs)

-{

-	ddef_t		*def;

-	int			i;

-	

-	for (i=0 ; i<progs->numfielddefs ; i++)

-	{

-		def = &pr_fielddefs[i];

-		if (def->ofs == ofs)

-			return def;

-	}

-	return NULL;

-}

-

-/*

-============

-ED_FindField

-============

-*/

-ddef_t *ED_FindField (char *name)

-{

-	ddef_t		*def;

-	int			i;

-	

-	for (i=0 ; i<progs->numfielddefs ; i++)

-	{

-		def = &pr_fielddefs[i];

-		if (!strcmp(pr_strings + def->s_name,name) )

-			return def;

-	}

-	return NULL;

-}

-

-

-/*

-============

-ED_FindGlobal

-============

-*/

-ddef_t *ED_FindGlobal (char *name)

-{

-	ddef_t		*def;

-	int			i;

-	

-	for (i=0 ; i<progs->numglobaldefs ; i++)

-	{

-		def = &pr_globaldefs[i];

-		if (!strcmp(pr_strings + def->s_name,name) )

-			return def;

-	}

-	return NULL;

-}

-

-

-/*

-============

-ED_FindFunction

-============

-*/

-dfunction_t *ED_FindFunction (char *name)

-{

-	dfunction_t		*func;

-	int				i;

-	

-	for (i=0 ; i<progs->numfunctions ; i++)

-	{

-		func = &pr_functions[i];

-		if (!strcmp(pr_strings + func->s_name,name) )

-			return func;

-	}

-	return NULL;

-}

-

-

-eval_t *GetEdictFieldValue(edict_t *ed, char *field)

-{

-	ddef_t			*def = NULL;

-	int				i;

-	static int		rep = 0;

-

-	for (i=0 ; i<GEFV_CACHESIZE ; i++)

-	{

-		if (!strcmp(field, gefvCache[i].field))

-		{

-			def = gefvCache[i].pcache;

-			goto Done;

-		}

-	}

-

-	def = ED_FindField (field);

-

-	if (strlen(field) < MAX_FIELD_LEN)

-	{

-		gefvCache[rep].pcache = def;

-		strcpy (gefvCache[rep].field, field);

-		rep ^= 1;

-	}

-

-Done:

-	if (!def)

-		return NULL;

-

-	return (eval_t *)((char *)&ed->v + def->ofs*4);

-}

-

-

-/*

-============

-PR_ValueString

-

-Returns a string describing *data in a type specific manner

-=============

-*/

-char *PR_ValueString (etype_t type, eval_t *val)

-{

-	static char	line[256];

-	ddef_t		*def;

-	dfunction_t	*f;

-	

-	type &= ~DEF_SAVEGLOBAL;

-

-	switch (type)

-	{

-	case ev_string:

-		sprintf (line, "%s", pr_strings + val->string);

-		break;

-	case ev_entity:	

-		sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );

-		break;

-	case ev_function:

-		f = pr_functions + val->function;

-		sprintf (line, "%s()", pr_strings + f->s_name);

-		break;

-	case ev_field:

-		def = ED_FieldAtOfs ( val->_int );

-		sprintf (line, ".%s", pr_strings + def->s_name);

-		break;

-	case ev_void:

-		sprintf (line, "void");

-		break;

-	case ev_float:

-		sprintf (line, "%5.1f", val->_float);

-		break;

-	case ev_vector:

-		sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]);

-		break;

-	case ev_pointer:

-		sprintf (line, "pointer");

-		break;

-	default:

-		sprintf (line, "bad type %i", type);

-		break;

-	}

-	

-	return line;

-}

-

-/*

-============

-PR_UglyValueString

-

-Returns a string describing *data in a type specific manner

-Easier to parse than PR_ValueString

-=============

-*/

-char *PR_UglyValueString (etype_t type, eval_t *val)

-{

-	static char	line[256];

-	ddef_t		*def;

-	dfunction_t	*f;

-	

-	type &= ~DEF_SAVEGLOBAL;

-

-	switch (type)

-	{

-	case ev_string:

-		sprintf (line, "%s", pr_strings + val->string);

-		break;

-	case ev_entity:	

-		sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)));

-		break;

-	case ev_function:

-		f = pr_functions + val->function;

-		sprintf (line, "%s", pr_strings + f->s_name);

-		break;

-	case ev_field:

-		def = ED_FieldAtOfs ( val->_int );

-		sprintf (line, "%s", pr_strings + def->s_name);

-		break;

-	case ev_void:

-		sprintf (line, "void");

-		break;

-	case ev_float:

-		sprintf (line, "%f", val->_float);

-		break;

-	case ev_vector:

-		sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);

-		break;

-	default:

-		sprintf (line, "bad type %i", type);

-		break;

-	}

-	

-	return line;

-}

-

-/*

-============

-PR_GlobalString

-

-Returns a string with a description and the contents of a global,

-padded to 20 field width

-============

-*/

-char *PR_GlobalString (int ofs)

-{

-	char	*s;

-	int		i;

-	ddef_t	*def;

-	void	*val;

-	static char	line[128];

-	

-	val = (void *)&pr_globals[ofs];

-	def = ED_GlobalAtOfs(ofs);

-	if (!def)

-		sprintf (line,"%i(???)", ofs);

-	else

-	{

-		s = PR_ValueString (def->type, val);

-		sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s);

-	}

-	

-	i = strlen(line);

-	for ( ; i<20 ; i++)

-		strcat (line," ");

-	strcat (line," ");

-		

-	return line;

-}

-

-char *PR_GlobalStringNoContents (int ofs)

-{

-	int		i;

-	ddef_t	*def;

-	static char	line[128];

-	

-	def = ED_GlobalAtOfs(ofs);

-	if (!def)

-		sprintf (line,"%i(???)", ofs);

-	else

-		sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name);

-	

-	i = strlen(line);

-	for ( ; i<20 ; i++)

-		strcat (line," ");

-	strcat (line," ");

-		

-	return line;

-}

-

-

-/*

-=============

-ED_Print

-

-For debugging

-=============

-*/

-void ED_Print (edict_t *ed)

-{

-	int		l;

-	ddef_t	*d;

-	int		*v;

-	int		i, j;

-	char	*name;

-	int		type;

-

-	if (ed->free)

-	{

-		Con_Printf ("FREE\n");

-		return;

-	}

-

-	Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed));

-	for (i=1 ; i<progs->numfielddefs ; i++)

-	{

-		d = &pr_fielddefs[i];

-		name = pr_strings + d->s_name;

-		if (name[strlen(name)-2] == '_')

-			continue;	// skip _x, _y, _z vars

-			

-		v = (int *)((char *)&ed->v + d->ofs*4);

-

-	// if the value is still all 0, skip the field

-		type = d->type & ~DEF_SAVEGLOBAL;

-		

-		for (j=0 ; j<type_size[type] ; j++)

-			if (v[j])

-				break;

-		if (j == type_size[type])

-			continue;

-	

-		Con_Printf ("%s",name);

-		l = strlen (name);

-		while (l++ < 15)

-			Con_Printf (" ");

-

-		Con_Printf ("%s\n", PR_ValueString(d->type, (eval_t *)v));		

-	}

-}

-

-/*

-=============

-ED_Write

-

-For savegames

-=============

-*/

-void ED_Write (FILE *f, edict_t *ed)

-{

-	ddef_t	*d;

-	int		*v;

-	int		i, j;

-	char	*name;

-	int		type;

-

-	fprintf (f, "{\n");

-

-	if (ed->free)

-	{

-		fprintf (f, "}\n");

-		return;

-	}

-	

-	for (i=1 ; i<progs->numfielddefs ; i++)

-	{

-		d = &pr_fielddefs[i];

-		name = pr_strings + d->s_name;

-		if (name[strlen(name)-2] == '_')

-			continue;	// skip _x, _y, _z vars

-			

-		v = (int *)((char *)&ed->v + d->ofs*4);

-

-	// if the value is still all 0, skip the field

-		type = d->type & ~DEF_SAVEGLOBAL;

-		for (j=0 ; j<type_size[type] ; j++)

-			if (v[j])

-				break;

-		if (j == type_size[type])

-			continue;

-	

-		fprintf (f,"\"%s\" ",name);

-		fprintf (f,"\"%s\"\n", PR_UglyValueString(d->type, (eval_t *)v));		

-	}

-

-	fprintf (f, "}\n");

-}

-

-void ED_PrintNum (int ent)

-{

-	ED_Print (EDICT_NUM(ent));

-}

-

-/*

-=============

-ED_PrintEdicts

-

-For debugging, prints all the entities in the current server

-=============

-*/

-void ED_PrintEdicts (void)

-{

-	int		i;

-	

-	Con_Printf ("%i entities\n", sv.num_edicts);

-	for (i=0 ; i<sv.num_edicts ; i++)

-		ED_PrintNum (i);

-}

-

-/*

-=============

-ED_PrintEdict_f

-

-For debugging, prints a single edicy

-=============

-*/

-void ED_PrintEdict_f (void)

-{

-	int		i;

-	

-	i = Q_atoi (Cmd_Argv(1));

-	if (i >= sv.num_edicts)

-	{

-		Con_Printf("Bad edict number\n");

-		return;

-	}

-	ED_PrintNum (i);

-}

-

-/*

-=============

-ED_Count

-

-For debugging

-=============

-*/

-void ED_Count (void)

-{

-	int		i;

-	edict_t	*ent;

-	int		active, models, solid, step;

-

-	active = models = solid = step = 0;

-	for (i=0 ; i<sv.num_edicts ; i++)

-	{

-		ent = EDICT_NUM(i);

-		if (ent->free)

-			continue;

-		active++;

-		if (ent->v.solid)

-			solid++;

-		if (ent->v.model)

-			models++;

-		if (ent->v.movetype == MOVETYPE_STEP)

-			step++;

-	}

-

-	Con_Printf ("num_edicts:%3i\n", sv.num_edicts);

-	Con_Printf ("active    :%3i\n", active);

-	Con_Printf ("view      :%3i\n", models);

-	Con_Printf ("touch     :%3i\n", solid);

-	Con_Printf ("step      :%3i\n", step);

-

-}

-

-/*

-==============================================================================

-

-					ARCHIVING GLOBALS

-

-FIXME: need to tag constants, doesn't really work

-==============================================================================

-*/

-

-/*

-=============

-ED_WriteGlobals

-=============

-*/

-void ED_WriteGlobals (FILE *f)

-{

-	ddef_t		*def;

-	int			i;

-	char		*name;

-	int			type;

-

-	fprintf (f,"{\n");

-	for (i=0 ; i<progs->numglobaldefs ; i++)

-	{

-		def = &pr_globaldefs[i];

-		type = def->type;

-		if ( !(def->type & DEF_SAVEGLOBAL) )

-			continue;

-		type &= ~DEF_SAVEGLOBAL;

-

-		if (type != ev_string

-		&& type != ev_float

-		&& type != ev_entity)

-			continue;

-

-		name = pr_strings + def->s_name;		

-		fprintf (f,"\"%s\" ", name);

-		fprintf (f,"\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs]));		

-	}

-	fprintf (f,"}\n");

-}

-

-/*

-=============

-ED_ParseGlobals

-=============

-*/

-void ED_ParseGlobals (char *data)

-{

-	char	keyname[64];

-	ddef_t	*key;

-

-	while (1)

-	{	

-	// parse key

-		data = COM_Parse (data);

-		if (com_token[0] == '}')

-			break;

-		if (!data)

-			Sys_Error ("ED_ParseEntity: EOF without closing brace");

-

-		strcpy (keyname, com_token);

-

-	// parse value	

-		data = COM_Parse (data);

-		if (!data)

-			Sys_Error ("ED_ParseEntity: EOF without closing brace");

-

-		if (com_token[0] == '}')

-			Sys_Error ("ED_ParseEntity: closing brace without data");

-

-		key = ED_FindGlobal (keyname);

-		if (!key)

-		{

-			Con_Printf ("'%s' is not a global\n", keyname);

-			continue;

-		}

-

-		if (!ED_ParseEpair ((void *)pr_globals, key, com_token))

-			Host_Error ("ED_ParseGlobals: parse error");

-	}

-}

-

-//============================================================================

-

-

-/*

-=============

-ED_NewString

-=============

-*/

-char *ED_NewString (char *string)

-{

-	char	*new, *new_p;

-	int		i,l;

-	

-	l = strlen(string) + 1;

-	new = Hunk_Alloc (l);

-	new_p = new;

-

-	for (i=0 ; i< l ; i++)

-	{

-		if (string[i] == '\\' && i < l-1)

-		{

-			i++;

-			if (string[i] == 'n')

-				*new_p++ = '\n';

-			else

-				*new_p++ = '\\';

-		}

-		else

-			*new_p++ = string[i];

-	}

-	

-	return new;

-}

-

-

-/*

-=============

-ED_ParseEval

-

-Can parse either fields or globals

-returns false if error

-=============

-*/

-qboolean	ED_ParseEpair (void *base, ddef_t *key, char *s)

-{

-	int		i;

-	char	string[128];

-	ddef_t	*def;

-	char	*v, *w;

-	void	*d;

-	dfunction_t	*func;

-	

-	d = (void *)((int *)base + key->ofs);

-	

-	switch (key->type & ~DEF_SAVEGLOBAL)

-	{

-	case ev_string:

-		*(string_t *)d = ED_NewString (s) - pr_strings;

-		break;

-		

-	case ev_float:

-		*(float *)d = atof (s);

-		break;

-		

-	case ev_vector:

-		strcpy (string, s);

-		v = string;

-		w = string;

-		for (i=0 ; i<3 ; i++)

-		{

-			while (*v && *v != ' ')

-				v++;

-			*v = 0;

-			((float *)d)[i] = atof (w);

-			w = v = v+1;

-		}

-		break;

-		

-	case ev_entity:

-		*(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));

-		break;

-		

-	case ev_field:

-		def = ED_FindField (s);

-		if (!def)

-		{

-			Con_Printf ("Can't find field %s\n", s);

-			return false;

-		}

-		*(int *)d = G_INT(def->ofs);

-		break;

-	

-	case ev_function:

-		func = ED_FindFunction (s);

-		if (!func)

-		{

-			Con_Printf ("Can't find function %s\n", s);

-			return false;

-		}

-		*(func_t *)d = func - pr_functions;

-		break;

-		

-	default:

-		break;

-	}

-	return true;

-}

-

-/*

-====================

-ED_ParseEdict

-

-Parses an edict out of the given string, returning the new position

-ed should be a properly initialized empty edict.

-Used for initial level load and for savegames.

-====================

-*/

-char *ED_ParseEdict (char *data, edict_t *ent)

-{

-	ddef_t		*key;

-	qboolean	anglehack;

-	qboolean	init;

-	char		keyname[256];

-	int			n;

-

-	init = false;

-

-// clear it

-	if (ent != sv.edicts)	// hack

-		memset (&ent->v, 0, progs->entityfields * 4);

-

-// go through all the dictionary pairs

-	while (1)

-	{	

-	// parse key

-		data = COM_Parse (data);

-		if (com_token[0] == '}')

-			break;

-		if (!data)

-			Sys_Error ("ED_ParseEntity: EOF without closing brace");

-		

-// anglehack is to allow QuakeEd to write single scalar angles

-// and allow them to be turned into vectors. (FIXME...)

-if (!strcmp(com_token, "angle"))

-{

-	strcpy (com_token, "angles");

-	anglehack = true;

-}

-else

-	anglehack = false;

-

-// FIXME: change light to _light to get rid of this hack

-if (!strcmp(com_token, "light"))

-	strcpy (com_token, "light_lev");	// hack for single light def

-

-		strcpy (keyname, com_token);

-

-		// another hack to fix heynames with trailing spaces

-		n = strlen(keyname);

-		while (n && keyname[n-1] == ' ')

-		{

-			keyname[n-1] = 0;

-			n--;

-		}

-

-	// parse value	

-		data = COM_Parse (data);

-		if (!data)

-			Sys_Error ("ED_ParseEntity: EOF without closing brace");

-

-		if (com_token[0] == '}')

-			Sys_Error ("ED_ParseEntity: closing brace without data");

-

-		init = true;	

-

-// keynames with a leading underscore are used for utility comments,

-// and are immediately discarded by quake

-		if (keyname[0] == '_')

-			continue;

-		

-		key = ED_FindField (keyname);

-		if (!key)

-		{

-			Con_Printf ("'%s' is not a field\n", keyname);

-			continue;

-		}

-

-if (anglehack)

-{

-char	temp[32];

-strcpy (temp, com_token);

-sprintf (com_token, "0 %s 0", temp);

-}

-

-		if (!ED_ParseEpair ((void *)&ent->v, key, com_token))

-			Host_Error ("ED_ParseEdict: parse error");

-	}

-

-	if (!init)

-		ent->free = true;

-

-	return data;

-}

-

-

-/*

-================

-ED_LoadFromFile

-

-The entities are directly placed in the array, rather than allocated with

-ED_Alloc, because otherwise an error loading the map would have entity

-number references out of order.

-

-Creates a server's entity / program execution context by

-parsing textual entity definitions out of an ent file.

-

-Used for both fresh maps and savegame loads.  A fresh map would also need

-to call ED_CallSpawnFunctions () to let the objects initialize themselves.

-================

-*/

-void ED_LoadFromFile (char *data)

-{	

-	edict_t		*ent;

-	int			inhibit;

-	dfunction_t	*func;

-	

-	ent = NULL;

-	inhibit = 0;

-	pr_global_struct->time = sv.time;

-	

-// parse ents

-	while (1)

-	{

-// parse the opening brace	

-		data = COM_Parse (data);

-		if (!data)

-			break;

-		if (com_token[0] != '{')

-			Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token);

-

-		if (!ent)

-			ent = EDICT_NUM(0);

-		else

-			ent = ED_Alloc ();

-		data = ED_ParseEdict (data, ent);

-

-// remove things from different skill levels or deathmatch

-		if (deathmatch.value)

-		{

-			if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))

-			{

-				ED_Free (ent);	

-				inhibit++;

-				continue;

-			}

-		}

-		else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY))

-				|| (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM))

-				|| (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) )

-		{

-			ED_Free (ent);	

-			inhibit++;

-			continue;

-		}

-

-//

-// immediately call spawn function

-//

-		if (!ent->v.classname)

-		{

-			Con_Printf ("No classname for:\n");

-			ED_Print (ent);

-			ED_Free (ent);

-			continue;

-		}

-

-	// look for the spawn function

-		func = ED_FindFunction ( pr_strings + ent->v.classname );

-

-		if (!func)

-		{

-			Con_Printf ("No spawn function for:\n");

-			ED_Print (ent);

-			ED_Free (ent);

-			continue;

-		}

-

-		pr_global_struct->self = EDICT_TO_PROG(ent);

-		PR_ExecuteProgram (func - pr_functions);

-	}	

-

-	Con_DPrintf ("%i entities inhibited\n", inhibit);

-}

-

-

-/*

-===============

-PR_LoadProgs

-===============

-*/

-void PR_LoadProgs (void)

-{

-	int		i;

-

-// flush the non-C variable lookup cache

-	for (i=0 ; i<GEFV_CACHESIZE ; i++)

-		gefvCache[i].field[0] = 0;

-

-	CRC_Init (&pr_crc);

-

-	progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat");

-	if (!progs)

-		Sys_Error ("PR_LoadProgs: couldn't load progs.dat");

-	Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);

-

-	for (i=0 ; i<com_filesize ; i++)

-		CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]);

-

-// byte swap the header

-	for (i=0 ; i<sizeof(*progs)/4 ; i++)

-		((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );		

-

-	if (progs->version != PROG_VERSION)

-		Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);

-	if (progs->crc != PROGHEADER_CRC)

-		Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date");

-

-	pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);

-	pr_strings = (char *)progs + progs->ofs_strings;

-	pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);

-	pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);

-	pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);

-

-	pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);

-	pr_globals = (float *)pr_global_struct;

-	

-	pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);

-	

-// byte swap the lumps

-	for (i=0 ; i<progs->numstatements ; i++)

-	{

-		pr_statements[i].op = LittleShort(pr_statements[i].op);

-		pr_statements[i].a = LittleShort(pr_statements[i].a);

-		pr_statements[i].b = LittleShort(pr_statements[i].b);

-		pr_statements[i].c = LittleShort(pr_statements[i].c);

-	}

-

-	for (i=0 ; i<progs->numfunctions; i++)

-	{

-	pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);

-	pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);

-	pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);

-	pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);

-	pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);

-	pr_functions[i].locals = LittleLong (pr_functions[i].locals);

-	}	

-

-	for (i=0 ; i<progs->numglobaldefs ; i++)

-	{

-		pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);

-		pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);

-		pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);

-	}

-

-	for (i=0 ; i<progs->numfielddefs ; i++)

-	{

-		pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);

-		if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)

-			Sys_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");

-		pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);

-		pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);

-	}

-

-	for (i=0 ; i<progs->numglobals ; i++)

-		((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);

-}

-

-

-/*

-===============

-PR_Init

-===============

-*/

-void PR_Init (void)

-{

-	Cmd_AddCommand ("edict", ED_PrintEdict_f);

-	Cmd_AddCommand ("edicts", ED_PrintEdicts);

-	Cmd_AddCommand ("edictcount", ED_Count);

-	Cmd_AddCommand ("profile", PR_Profile_f);

-	Cvar_RegisterVariable (&nomonsters);

-	Cvar_RegisterVariable (&gamecfg);

-	Cvar_RegisterVariable (&scratch1);

-	Cvar_RegisterVariable (&scratch2);

-	Cvar_RegisterVariable (&scratch3);

-	Cvar_RegisterVariable (&scratch4);

-	Cvar_RegisterVariable (&savedgamecfg);

-	Cvar_RegisterVariable (&saved1);

-	Cvar_RegisterVariable (&saved2);

-	Cvar_RegisterVariable (&saved3);

-	Cvar_RegisterVariable (&saved4);

-}

-

-

-

-edict_t *EDICT_NUM(int n)

-{

-	if (n < 0 || n >= sv.max_edicts)

-		Sys_Error ("EDICT_NUM: bad number %i", n);

-	return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size);

-}

-

-int NUM_FOR_EDICT(edict_t *e)

-{

-	int		b;

-	

-	b = (byte *)e - (byte *)sv.edicts;

-	b = b / pr_edict_size;

-	

-	if (b < 0 || b >= sv.num_edicts)

-		Sys_Error ("NUM_FOR_EDICT: bad pointer");

-	return b;

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// sv_edict.c -- entity dictionary
+
+#include "quakedef.h"
+
+dprograms_t		*progs;
+dfunction_t		*pr_functions;
+char			*pr_strings;
+ddef_t			*pr_fielddefs;
+ddef_t			*pr_globaldefs;
+dstatement_t	*pr_statements;
+globalvars_t	*pr_global_struct;
+float			*pr_globals;			// same as pr_global_struct
+int				pr_edict_size;	// in bytes
+
+unsigned short		pr_crc;
+
+int		type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
+
+ddef_t *ED_FieldAtOfs (int ofs);
+qboolean	ED_ParseEpair (void *base, ddef_t *key, char *s);
+
+cvar_t	nomonsters = CVAR2("nomonsters", "0");
+cvar_t	gamecfg = CVAR2("gamecfg", "0");
+cvar_t	scratch1 = CVAR2("scratch1", "0");
+cvar_t	scratch2 = CVAR2("scratch2", "0");
+cvar_t	scratch3 = CVAR2("scratch3", "0");
+cvar_t	scratch4 = CVAR2("scratch4", "0");
+cvar_t	savedgamecfg = CVAR3("savedgamecfg", "0", true);
+cvar_t	saved1 = CVAR3("saved1", "0", true);
+cvar_t	saved2 = CVAR3("saved2", "0", true);
+cvar_t	saved3 = CVAR3("saved3", "0", true);
+cvar_t	saved4 = CVAR3("saved4", "0", true);
+
+#define	MAX_FIELD_LEN	64
+#define GEFV_CACHESIZE	2
+
+typedef struct {
+	ddef_t	*pcache;
+	char	field[MAX_FIELD_LEN];
+} gefv_cache;
+
+static gefv_cache	gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}};
+
+/*
+=================
+ED_ClearEdict
+
+Sets everything to NULL
+=================
+*/
+void ED_ClearEdict (edict_t *e)
+{
+	memset (&e->u.v, 0, progs->entityfields * 4);
+	e->free = false;
+}
+
+/*
+=================
+ED_Alloc
+
+Either finds a free edict, or allocates a new one.
+Try to avoid reusing an entity that was recently freed, because it
+can cause the client to think the entity morphed into something else
+instead of being removed and recreated, which can cause interpolated
+angles and bad trails.
+=================
+*/
+edict_t *ED_Alloc (void)
+{
+	int			i;
+	edict_t		*e;
+
+	for ( i=svs.maxclients+1 ; i<sv.num_edicts ; i++)
+	{
+		e = EDICT_NUM(i);
+		// the first couple seconds of server time can involve a lot of
+		// freeing and allocating, so relax the replacement policy
+		if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )
+		{
+			ED_ClearEdict (e);
+			return e;
+		}
+	}
+	
+	if (i == MAX_EDICTS)
+		Sys_Error ("ED_Alloc: no free edicts");
+		
+	sv.num_edicts++;
+	e = EDICT_NUM(i);
+	ED_ClearEdict (e);
+
+	return e;
+}
+
+/*
+=================
+ED_Free
+
+Marks the edict as free
+FIXME: walk all entities and NULL out references to this entity
+=================
+*/
+void ED_Free (edict_t *ed)
+{
+	SV_UnlinkEdict (ed);		// unlink from world bsp
+
+	ed->free = true;
+	ed->u.v.model = 0;
+	ed->u.v.takedamage = 0;
+	ed->u.v.modelindex = 0;
+	ed->u.v.colormap = 0;
+	ed->u.v.skin = 0;
+	ed->u.v.frame = 0;
+	VectorCopy (vec3_origin, ed->u.v.origin);
+	VectorCopy (vec3_origin, ed->u.v.angles);
+	ed->u.v.nextthink = -1;
+	ed->u.v.solid = 0;
+	
+	ed->freetime = sv.time;
+}
+
+//===========================================================================
+
+/*
+============
+ED_GlobalAtOfs
+============
+*/
+ddef_t *ED_GlobalAtOfs (int ofs)
+{
+	ddef_t		*def;
+	int			i;
+	
+	for (i=0 ; i<progs->numglobaldefs ; i++)
+	{
+		def = &pr_globaldefs[i];
+		if (def->ofs == ofs)
+			return def;
+	}
+	return NULL;
+}
+
+/*
+============
+ED_FieldAtOfs
+============
+*/
+ddef_t *ED_FieldAtOfs (int ofs)
+{
+	ddef_t		*def;
+	int			i;
+	
+	for (i=0 ; i<progs->numfielddefs ; i++)
+	{
+		def = &pr_fielddefs[i];
+		if (def->ofs == ofs)
+			return def;
+	}
+	return NULL;
+}
+
+/*
+============
+ED_FindField
+============
+*/
+ddef_t *ED_FindField (const char *name)
+{
+	ddef_t		*def;
+	int			i;
+	
+	for (i=0 ; i<progs->numfielddefs ; i++)
+	{
+		def = &pr_fielddefs[i];
+		if (!strcmp(pr_strings + def->s_name,name) )
+			return def;
+	}
+	return NULL;
+}
+
+
+/*
+============
+ED_FindGlobal
+============
+*/
+ddef_t *ED_FindGlobal (const char *name)
+{
+	ddef_t		*def;
+	int			i;
+	
+	for (i=0 ; i<progs->numglobaldefs ; i++)
+	{
+		def = &pr_globaldefs[i];
+		if (!strcmp(pr_strings + def->s_name,name) )
+			return def;
+	}
+	return NULL;
+}
+
+
+/*
+============
+ED_FindFunction
+============
+*/
+dfunction_t *ED_FindFunction (const char *name)
+{
+	dfunction_t		*func;
+	int				i;
+	
+	for (i=0 ; i<progs->numfunctions ; i++)
+	{
+		func = &pr_functions[i];
+		if (!strcmp(pr_strings + func->s_name,name) )
+			return func;
+	}
+	return NULL;
+}
+
+
+eval_t *GetEdictFieldValue(edict_t *ed, const char *field)
+{
+	ddef_t			*def = NULL;
+	int				i;
+	static int		rep = 0;
+
+	for (i=0 ; i<GEFV_CACHESIZE ; i++)
+	{
+		if (!strcmp(field, gefvCache[i].field))
+		{
+			def = gefvCache[i].pcache;
+			goto Done;
+		}
+	}
+
+	def = ED_FindField (field);
+
+	if (strlen(field) < MAX_FIELD_LEN)
+	{
+		gefvCache[rep].pcache = def;
+		strcpy (gefvCache[rep].field, field);
+		rep ^= 1;
+	}
+
+Done:
+	if (!def)
+		return NULL;
+
+	return (eval_t *)((char *)&ed->u.v + def->ofs*4);
+}
+
+
+/*
+============
+PR_ValueString
+
+Returns a string describing *data in a type specific manner
+=============
+*/
+char *PR_ValueString (etype_t type, eval_t *val)
+{
+	static char	line[256];
+	ddef_t		*def;
+	dfunction_t	*f;
+	
+	type = (etype_t) (type & ~DEF_SAVEGLOBAL);
+
+	switch (type)
+	{
+	case ev_string:
+		sprintf (line, "%s", pr_strings + val->string);
+		break;
+	case ev_entity:	
+		sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );
+		break;
+	case ev_function:
+		f = pr_functions + val->function;
+		sprintf (line, "%s()", pr_strings + f->s_name);
+		break;
+	case ev_field:
+		def = ED_FieldAtOfs ( val->_int );
+		sprintf (line, ".%s", pr_strings + def->s_name);
+		break;
+	case ev_void:
+		sprintf (line, "void");
+		break;
+	case ev_float:
+		sprintf (line, "%5.1f", val->_float);
+		break;
+	case ev_vector:
+		sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]);
+		break;
+	case ev_pointer:
+		sprintf (line, "pointer");
+		break;
+	default:
+		sprintf (line, "bad type %i", type);
+		break;
+	}
+	
+	return line;
+}
+
+/*
+============
+PR_UglyValueString
+
+Returns a string describing *data in a type specific manner
+Easier to parse than PR_ValueString
+=============
+*/
+char *PR_UglyValueString (etype_t type, eval_t *val)
+{
+	static char	line[256];
+	ddef_t		*def;
+	dfunction_t	*f;
+	
+	type = (etype_t) (type & ~DEF_SAVEGLOBAL);
+
+	switch (type)
+	{
+	case ev_string:
+		sprintf (line, "%s", pr_strings + val->string);
+		break;
+	case ev_entity:	
+		sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)));
+		break;
+	case ev_function:
+		f = pr_functions + val->function;
+		sprintf (line, "%s", pr_strings + f->s_name);
+		break;
+	case ev_field:
+		def = ED_FieldAtOfs ( val->_int );
+		sprintf (line, "%s", pr_strings + def->s_name);
+		break;
+	case ev_void:
+		sprintf (line, "void");
+		break;
+	case ev_float:
+		sprintf (line, "%f", val->_float);
+		break;
+	case ev_vector:
+		sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
+		break;
+	default:
+		sprintf (line, "bad type %i", type);
+		break;
+	}
+	
+	return line;
+}
+
+/*
+============
+PR_GlobalString
+
+Returns a string with a description and the contents of a global,
+padded to 20 field width
+============
+*/
+char *PR_GlobalString (int ofs)
+{
+	char	*s;
+	int		i;
+	ddef_t	*def;
+	void	*val;
+	static char	line[128];
+	
+	val = (void *)&pr_globals[ofs];
+	def = ED_GlobalAtOfs(ofs);
+	if (!def)
+		sprintf (line,"%i(??""?)", ofs);
+	else
+	{
+		s = PR_ValueString ((etype_t) def->type, (eval_t*) val);
+		sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s);
+	}
+	
+	i = strlen(line);
+	for ( ; i<20 ; i++)
+		strcat (line," ");
+	strcat (line," ");
+		
+	return line;
+}
+
+char *PR_GlobalStringNoContents (int ofs)
+{
+	int		i;
+	ddef_t	*def;
+	static char	line[128];
+	
+	def = ED_GlobalAtOfs(ofs);
+	if (!def)
+		sprintf (line,"%i(??""?)", ofs);
+	else
+		sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name);
+	
+	i = strlen(line);
+	for ( ; i<20 ; i++)
+		strcat (line," ");
+	strcat (line," ");
+		
+	return line;
+}
+
+
+/*
+=============
+ED_Print
+
+For debugging
+=============
+*/
+void ED_Print (edict_t *ed)
+{
+	int		l;
+	ddef_t	*d;
+	int		*v;
+	int		i, j;
+	char	*name;
+	int		type;
+
+	if (ed->free)
+	{
+		Con_Printf ("FREE\n");
+		return;
+	}
+
+	Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed));
+	for (i=1 ; i<progs->numfielddefs ; i++)
+	{
+		d = &pr_fielddefs[i];
+		name = pr_strings + d->s_name;
+		if (name[strlen(name)-2] == '_')
+			continue;	// skip _x, _y, _z vars
+			
+		v = (int *)((char *)&ed->u.v + d->ofs*4);
+
+	// if the value is still all 0, skip the field
+		type = d->type & ~DEF_SAVEGLOBAL;
+		
+		for (j=0 ; j<type_size[type] ; j++)
+			if (v[j])
+				break;
+		if (j == type_size[type])
+			continue;
+	
+		Con_Printf ("%s",name);
+		l = strlen (name);
+		while (l++ < 15)
+			Con_Printf (" ");
+
+		Con_Printf ("%s\n", PR_ValueString((etype_t) d->type, (eval_t *)v));		
+	}
+}
+
+/*
+=============
+ED_Write
+
+For savegames
+=============
+*/
+void ED_Write (FILE *f, edict_t *ed)
+{
+	ddef_t	*d;
+	int		*v;
+	int		i, j;
+	char	*name;
+	int		type;
+
+	fprintf (f, "{\n");
+
+	if (ed->free)
+	{
+		fprintf (f, "}\n");
+		return;
+	}
+	
+	for (i=1 ; i<progs->numfielddefs ; i++)
+	{
+		d = &pr_fielddefs[i];
+		name = pr_strings + d->s_name;
+		if (name[strlen(name)-2] == '_')
+			continue;	// skip _x, _y, _z vars
+			
+		v = (int *)((char *)&ed->u.v + d->ofs*4);
+
+	// if the value is still all 0, skip the field
+		type = d->type & ~DEF_SAVEGLOBAL;
+		for (j=0 ; j<type_size[type] ; j++)
+			if (v[j])
+				break;
+		if (j == type_size[type])
+			continue;
+	
+		fprintf (f,"\"%s\" ",name);
+		fprintf (f,"\"%s\"\n", PR_UglyValueString((etype_t) d->type, (eval_t *)v));		
+	}
+
+	fprintf (f, "}\n");
+}
+
+void ED_PrintNum (int ent)
+{
+	ED_Print (EDICT_NUM(ent));
+}
+
+/*
+=============
+ED_PrintEdicts
+
+For debugging, prints all the entities in the current server
+=============
+*/
+void ED_PrintEdicts (void)
+{
+	int		i;
+	
+	Con_Printf ("%i entities\n", sv.num_edicts);
+	for (i=0 ; i<sv.num_edicts ; i++)
+		ED_PrintNum (i);
+}
+
+/*
+=============
+ED_PrintEdict_f
+
+For debugging, prints a single edicy
+=============
+*/
+void ED_PrintEdict_f (void)
+{
+	int		i;
+	
+	i = Q_atoi (Cmd_Argv(1));
+	if (i >= sv.num_edicts)
+	{
+		Con_Printf("Bad edict number\n");
+		return;
+	}
+	ED_PrintNum (i);
+}
+
+/*
+=============
+ED_Count
+
+For debugging
+=============
+*/
+void ED_Count (void)
+{
+	int		i;
+	edict_t	*ent;
+	int		active, models, solid, step;
+
+	active = models = solid = step = 0;
+	for (i=0 ; i<sv.num_edicts ; i++)
+	{
+		ent = EDICT_NUM(i);
+		if (ent->free)
+			continue;
+		active++;
+		if (ent->u.v.solid)
+			solid++;
+		if (ent->u.v.model)
+			models++;
+		if (ent->u.v.movetype == MOVETYPE_STEP)
+			step++;
+	}
+
+	Con_Printf ("num_edicts:%3i\n", sv.num_edicts);
+	Con_Printf ("active    :%3i\n", active);
+	Con_Printf ("view      :%3i\n", models);
+	Con_Printf ("touch     :%3i\n", solid);
+	Con_Printf ("step      :%3i\n", step);
+
+}
+
+/*
+==============================================================================
+
+					ARCHIVING GLOBALS
+
+FIXME: need to tag constants, doesn't really work
+==============================================================================
+*/
+
+/*
+=============
+ED_WriteGlobals
+=============
+*/
+void ED_WriteGlobals (FILE *f)
+{
+	ddef_t		*def;
+	int			i;
+	char		*name;
+	int			type;
+
+	fprintf (f,"{\n");
+	for (i=0 ; i<progs->numglobaldefs ; i++)
+	{
+		def = &pr_globaldefs[i];
+		type = def->type;
+		if ( !(def->type & DEF_SAVEGLOBAL) )
+			continue;
+		type &= ~DEF_SAVEGLOBAL;
+
+		if (type != ev_string
+		&& type != ev_float
+		&& type != ev_entity)
+			continue;
+
+		name = pr_strings + def->s_name;		
+		fprintf (f,"\"%s\" ", name);
+		fprintf (f,"\"%s\"\n", PR_UglyValueString((etype_t) type, (eval_t *)&pr_globals[def->ofs]));		
+	}
+	fprintf (f,"}\n");
+}
+
+/*
+=============
+ED_ParseGlobals
+=============
+*/
+void ED_ParseGlobals (char *data)
+{
+	char	keyname[64];
+	ddef_t	*key;
+
+	while (1)
+	{	
+	// parse key
+		data = COM_Parse (data);
+		if (com_token[0] == '}')
+			break;
+		if (!data)
+			Sys_Error ("ED_ParseEntity: EOF without closing brace");
+
+		strcpy (keyname, com_token);
+
+	// parse value	
+		data = COM_Parse (data);
+		if (!data)
+			Sys_Error ("ED_ParseEntity: EOF without closing brace");
+
+		if (com_token[0] == '}')
+			Sys_Error ("ED_ParseEntity: closing brace without data");
+
+		key = ED_FindGlobal (keyname);
+		if (!key)
+		{
+			Con_Printf ("'%s' is not a global\n", keyname);
+			continue;
+		}
+
+		if (!ED_ParseEpair ((void *)pr_globals, key, com_token))
+			Host_Error ("ED_ParseGlobals: parse error");
+	}
+}
+
+//============================================================================
+
+
+/*
+=============
+ED_NewString
+=============
+*/
+char *ED_NewString (char *string)
+{
+	char	*new_, *new_p;
+	int		i,l;
+	
+	l = strlen(string) + 1;
+	new_ = (char*) Hunk_Alloc (l);
+	new_p = new_;
+
+	for (i=0 ; i< l ; i++)
+	{
+		if (string[i] == '\\' && i < l-1)
+		{
+			i++;
+			if (string[i] == 'n')
+				*new_p++ = '\n';
+			else
+				*new_p++ = '\\';
+		}
+		else
+			*new_p++ = string[i];
+	}
+	
+	return new_;
+}
+
+
+/*
+=============
+ED_ParseEval
+
+Can parse either fields or globals
+returns false if error
+=============
+*/
+qboolean	ED_ParseEpair (void *base, ddef_t *key, char *s)
+{
+	int		i;
+	char	string[128];
+	ddef_t	*def;
+	char	*v, *w;
+	void	*d;
+	dfunction_t	*func;
+	
+	d = (void *)((int *)base + key->ofs);
+	
+	switch (key->type & ~DEF_SAVEGLOBAL)
+	{
+	case ev_string:
+		*(string_t *)d = ED_NewString (s) - pr_strings;
+		break;
+		
+	case ev_float:
+		*(float *)d = atof (s);
+		break;
+		
+	case ev_vector:
+		strcpy (string, s);
+		v = string;
+		w = string;
+		for (i=0 ; i<3 ; i++)
+		{
+			while (*v && *v != ' ')
+				v++;
+			*v = 0;
+			((float *)d)[i] = atof (w);
+			w = v = v+1;
+		}
+		break;
+		
+	case ev_entity:
+		*(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));
+		break;
+		
+	case ev_field:
+		def = ED_FindField (s);
+		if (!def)
+		{
+			Con_Printf ("Can't find field %s\n", s);
+			return false;
+		}
+		*(int *)d = G_INT(def->ofs);
+		break;
+	
+	case ev_function:
+		func = ED_FindFunction (s);
+		if (!func)
+		{
+			Con_Printf ("Can't find function %s\n", s);
+			return false;
+		}
+		*(func_t *)d = func - pr_functions;
+		break;
+		
+	default:
+		break;
+	}
+	return true;
+}
+
+/*
+====================
+ED_ParseEdict
+
+Parses an edict out of the given string, returning the new position
+ed should be a properly initialized empty edict.
+Used for initial level load and for savegames.
+====================
+*/
+char *ED_ParseEdict (char *data, edict_t *ent)
+{
+	ddef_t		*key;
+	qboolean	anglehack;
+	qboolean	init;
+	char		keyname[256];
+	int			n;
+
+	init = false;
+
+// clear it
+	if (ent != sv.edicts)	// hack
+		memset (&ent->u.v, 0, progs->entityfields * 4);
+
+// go through all the dictionary pairs
+	while (1)
+	{	
+	// parse key
+		data = COM_Parse (data);
+		if (com_token[0] == '}')
+			break;
+		if (!data)
+			Sys_Error ("ED_ParseEntity: EOF without closing brace");
+		
+// anglehack is to allow QuakeEd to write single scalar angles
+// and allow them to be turned into vectors. (FIXME...)
+if (!strcmp(com_token, "angle"))
+{
+	strcpy (com_token, "angles");
+	anglehack = true;
+}
+else
+	anglehack = false;
+
+// FIXME: change light to _light to get rid of this hack
+if (!strcmp(com_token, "light"))
+	strcpy (com_token, "light_lev");	// hack for single light def
+
+		strcpy (keyname, com_token);
+
+		// another hack to fix heynames with trailing spaces
+		n = strlen(keyname);
+		while (n && keyname[n-1] == ' ')
+		{
+			keyname[n-1] = 0;
+			n--;
+		}
+
+	// parse value	
+		data = COM_Parse (data);
+		if (!data)
+			Sys_Error ("ED_ParseEntity: EOF without closing brace");
+
+		if (com_token[0] == '}')
+			Sys_Error ("ED_ParseEntity: closing brace without data");
+
+		init = true;	
+
+// keynames with a leading underscore are used for utility comments,
+// and are immediately discarded by quake
+		if (keyname[0] == '_')
+			continue;
+		
+		key = ED_FindField (keyname);
+		if (!key)
+		{
+			Con_Printf ("'%s' is not a field\n", keyname);
+			continue;
+		}
+
+if (anglehack)
+{
+char	temp[32];
+strcpy (temp, com_token);
+sprintf (com_token, "0 %s 0", temp);
+}
+
+		if (!ED_ParseEpair ((void *)&ent->u.v, key, com_token))
+			Host_Error ("ED_ParseEdict: parse error");
+	}
+
+	if (!init)
+		ent->free = true;
+
+	return data;
+}
+
+
+/*
+================
+ED_LoadFromFile
+
+The entities are directly placed in the array, rather than allocated with
+ED_Alloc, because otherwise an error loading the map would have entity
+number references out of order.
+
+Creates a server's entity / program execution context by
+parsing textual entity definitions out of an ent file.
+
+Used for both fresh maps and savegame loads.  A fresh map would also need
+to call ED_CallSpawnFunctions () to let the objects initialize themselves.
+================
+*/
+void ED_LoadFromFile (char *data)
+{	
+	edict_t		*ent;
+	int			inhibit;
+	dfunction_t	*func;
+	
+	ent = NULL;
+	inhibit = 0;
+	pr_global_struct->time = sv.time;
+	
+// parse ents
+	while (1)
+	{
+// parse the opening brace	
+		data = COM_Parse (data);
+		if (!data)
+			break;
+		if (com_token[0] != '{')
+			Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
+
+		if (!ent)
+			ent = EDICT_NUM(0);
+		else
+			ent = ED_Alloc ();
+		data = ED_ParseEdict (data, ent);
+
+// remove things from different skill levels or deathmatch
+		if (deathmatch.value)
+		{
+			if (((int)ent->u.v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
+			{
+				ED_Free (ent);	
+				inhibit++;
+				continue;
+			}
+		}
+		else if ((current_skill == 0 && ((int)ent->u.v.spawnflags & SPAWNFLAG_NOT_EASY))
+				|| (current_skill == 1 && ((int)ent->u.v.spawnflags & SPAWNFLAG_NOT_MEDIUM))
+				|| (current_skill >= 2 && ((int)ent->u.v.spawnflags & SPAWNFLAG_NOT_HARD)) )
+		{
+			ED_Free (ent);	
+			inhibit++;
+			continue;
+		}
+
+//
+// immediately call spawn function
+//
+		if (!ent->u.v.classname)
+		{
+			Con_Printf ("No classname for:\n");
+			ED_Print (ent);
+			ED_Free (ent);
+			continue;
+		}
+
+	// look for the spawn function
+		func = ED_FindFunction ( pr_strings + ent->u.v.classname );
+
+		if (!func)
+		{
+			Con_Printf ("No spawn function for:\n");
+			ED_Print (ent);
+			ED_Free (ent);
+			continue;
+		}
+
+		pr_global_struct->self = EDICT_TO_PROG(ent);
+		PR_ExecuteProgram (func - pr_functions);
+	}	
+
+	Con_DPrintf ("%i entities inhibited\n", inhibit);
+}
+
+
+/*
+===============
+PR_LoadProgs
+===============
+*/
+void PR_LoadProgs (void)
+{
+	int		i;
+
+// flush the non-C variable lookup cache
+	for (i=0 ; i<GEFV_CACHESIZE ; i++)
+		gefvCache[i].field[0] = 0;
+
+	CRC_Init (&pr_crc);
+
+	progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat");
+	if (!progs)
+		Sys_Error ("PR_LoadProgs: couldn't load progs.dat");
+	Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
+
+	for (i=0 ; i<com_filesize ; i++)
+		CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]);
+
+// byte swap the header
+	for (i=0 ; i< (int) (sizeof(*progs)/4) ; i++)
+		((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );		
+
+	if (progs->version != PROG_VERSION)
+		Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
+	if (progs->crc != PROGHEADER_CRC)
+		Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date");
+
+	pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
+	pr_strings = (char *)progs + progs->ofs_strings;
+	pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
+	pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
+	pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
+
+	pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
+	pr_globals = (float *)pr_global_struct;
+	
+	pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);
+	
+// byte swap the lumps
+	for (i=0 ; i<progs->numstatements ; i++)
+	{
+		pr_statements[i].op = LittleShort(pr_statements[i].op);
+		pr_statements[i].a = LittleShort(pr_statements[i].a);
+		pr_statements[i].b = LittleShort(pr_statements[i].b);
+		pr_statements[i].c = LittleShort(pr_statements[i].c);
+	}
+
+	for (i=0 ; i<progs->numfunctions; i++)
+	{
+	pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);
+	pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);
+	pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);
+	pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);
+	pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);
+	pr_functions[i].locals = LittleLong (pr_functions[i].locals);
+	}	
+
+	for (i=0 ; i<progs->numglobaldefs ; i++)
+	{
+		pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
+		pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
+		pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
+	}
+
+	for (i=0 ; i<progs->numfielddefs ; i++)
+	{
+		pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);
+		if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
+			Sys_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
+		pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
+		pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
+	}
+
+	for (i=0 ; i<progs->numglobals ; i++)
+		((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
+}
+
+
+/*
+===============
+PR_Init
+===============
+*/
+void PR_Init (void)
+{
+	Cmd_AddCommand ("edict", ED_PrintEdict_f);
+	Cmd_AddCommand ("edicts", ED_PrintEdicts);
+	Cmd_AddCommand ("edictcount", ED_Count);
+	Cmd_AddCommand ("profile", PR_Profile_f);
+	Cvar_RegisterVariable (&nomonsters);
+	Cvar_RegisterVariable (&gamecfg);
+	Cvar_RegisterVariable (&scratch1);
+	Cvar_RegisterVariable (&scratch2);
+	Cvar_RegisterVariable (&scratch3);
+	Cvar_RegisterVariable (&scratch4);
+	Cvar_RegisterVariable (&savedgamecfg);
+	Cvar_RegisterVariable (&saved1);
+	Cvar_RegisterVariable (&saved2);
+	Cvar_RegisterVariable (&saved3);
+	Cvar_RegisterVariable (&saved4);
+}
+
+
+
+edict_t *EDICT_NUM(int n)
+{
+	if (n < 0 || n >= sv.max_edicts)
+		Sys_Error ("EDICT_NUM: bad number %i", n);
+	return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size);
+}
+
+int NUM_FOR_EDICT(edict_t *e)
+{
+	int		b;
+	
+	b = (byte *)e - (byte *)sv.edicts;
+	b = b / pr_edict_size;
+	
+	if (b < 0 || b >= sv.num_edicts)
+		Sys_Error ("NUM_FOR_EDICT: bad pointer");
+	return b;
+}
diff --git a/quake/src/WinQuake/pr_exec.c b/quake/src/WinQuake/pr_exec.cpp
old mode 100644
new mode 100755
similarity index 96%
rename from quake/src/WinQuake/pr_exec.c
rename to quake/src/WinQuake/pr_exec.cpp
index 3fa0d29..2af657a
--- a/quake/src/WinQuake/pr_exec.c
+++ b/quake/src/WinQuake/pr_exec.cpp
@@ -1,668 +1,668 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-#include "quakedef.h"

-

-

-/*

-

-*/

-

-typedef struct

-{

-	int				s;

-	dfunction_t		*f;

-} prstack_t;

-

-#define	MAX_STACK_DEPTH		32

-prstack_t	pr_stack[MAX_STACK_DEPTH];

-int			pr_depth;

-

-#define	LOCALSTACK_SIZE		2048

-int			localstack[LOCALSTACK_SIZE];

-int			localstack_used;

-

-

-qboolean	pr_trace;

-dfunction_t	*pr_xfunction;

-int			pr_xstatement;

-

-

-int		pr_argc;

-

-char *pr_opnames[] =

-{

-"DONE",

-

-"MUL_F",

-"MUL_V", 

-"MUL_FV",

-"MUL_VF",

- 

-"DIV",

-

-"ADD_F",

-"ADD_V", 

-  

-"SUB_F",

-"SUB_V",

-

-"EQ_F",

-"EQ_V",

-"EQ_S", 

-"EQ_E",

-"EQ_FNC",

- 

-"NE_F",

-"NE_V", 

-"NE_S",

-"NE_E", 

-"NE_FNC",

- 

-"LE",

-"GE",

-"LT",

-"GT", 

-

-"INDIRECT",

-"INDIRECT",

-"INDIRECT", 

-"INDIRECT", 

-"INDIRECT",

-"INDIRECT", 

-

-"ADDRESS", 

-

-"STORE_F",

-"STORE_V",

-"STORE_S",

-"STORE_ENT",

-"STORE_FLD",

-"STORE_FNC",

-

-"STOREP_F",

-"STOREP_V",

-"STOREP_S",

-"STOREP_ENT",

-"STOREP_FLD",

-"STOREP_FNC",

-

-"RETURN",

-  

-"NOT_F",

-"NOT_V",

-"NOT_S", 

-"NOT_ENT", 

-"NOT_FNC", 

-  

-"IF",

-"IFNOT",

-  

-"CALL0",

-"CALL1",

-"CALL2",

-"CALL3",

-"CALL4",

-"CALL5",

-"CALL6",

-"CALL7",

-"CALL8",

-  

-"STATE",

-  

-"GOTO", 

-  

-"AND",

-"OR", 

-

-"BITAND",

-"BITOR"

-};

-

-char *PR_GlobalString (int ofs);

-char *PR_GlobalStringNoContents (int ofs);

-

-

-//=============================================================================

-

-/*

-=================

-PR_PrintStatement

-=================

-*/

-void PR_PrintStatement (dstatement_t *s)

-{

-	int		i;

-	

-	if ( (unsigned)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0]))

-	{

-		Con_Printf ("%s ",  pr_opnames[s->op]);

-		i = strlen(pr_opnames[s->op]);

-		for ( ; i<10 ; i++)

-			Con_Printf (" ");

-	}

-		

-	if (s->op == OP_IF || s->op == OP_IFNOT)

-		Con_Printf ("%sbranch %i",PR_GlobalString(s->a),s->b);

-	else if (s->op == OP_GOTO)

-	{

-		Con_Printf ("branch %i",s->a);

-	}

-	else if ( (unsigned)(s->op - OP_STORE_F) < 6)

-	{

-		Con_Printf ("%s",PR_GlobalString(s->a));

-		Con_Printf ("%s", PR_GlobalStringNoContents(s->b));

-	}

-	else

-	{

-		if (s->a)

-			Con_Printf ("%s",PR_GlobalString(s->a));

-		if (s->b)

-			Con_Printf ("%s",PR_GlobalString(s->b));

-		if (s->c)

-			Con_Printf ("%s", PR_GlobalStringNoContents(s->c));

-	}

-	Con_Printf ("\n");

-}

-

-/*

-============

-PR_StackTrace

-============

-*/

-void PR_StackTrace (void)

-{

-	dfunction_t	*f;

-	int			i;

-	

-	if (pr_depth == 0)

-	{

-		Con_Printf ("<NO STACK>\n");

-		return;

-	}

-	

-	pr_stack[pr_depth].f = pr_xfunction;

-	for (i=pr_depth ; i>=0 ; i--)

-	{

-		f = pr_stack[i].f;

-		

-		if (!f)

-		{

-			Con_Printf ("<NO FUNCTION>\n");

-		}

-		else

-			Con_Printf ("%12s : %s\n", pr_strings + f->s_file, pr_strings + f->s_name);		

-	}

-}

-

-

-/*

-============

-PR_Profile_f

-

-============

-*/

-void PR_Profile_f (void)

-{

-	dfunction_t	*f, *best;

-	int			max;

-	int			num;

-	int			i;

-	

-	num = 0;	

-	do

-	{

-		max = 0;

-		best = NULL;

-		for (i=0 ; i<progs->numfunctions ; i++)

-		{

-			f = &pr_functions[i];

-			if (f->profile > max)

-			{

-				max = f->profile;

-				best = f;

-			}

-		}

-		if (best)

-		{

-			if (num < 10)

-				Con_Printf ("%7i %s\n", best->profile, pr_strings+best->s_name);

-			num++;

-			best->profile = 0;

-		}

-	} while (best);

-}

-

-

-/*

-============

-PR_RunError

-

-Aborts the currently executing function

-============

-*/

-void PR_RunError (char *error, ...)

-{

-	va_list		argptr;

-	char		string[1024];

-

-	va_start (argptr,error);

-	vsprintf (string,error,argptr);

-	va_end (argptr);

-

-	PR_PrintStatement (pr_statements + pr_xstatement);

-	PR_StackTrace ();

-	Con_Printf ("%s\n", string);

-	

-	pr_depth = 0;		// dump the stack so host_error can shutdown functions

-

-	Host_Error ("Program error");

-}

-

-/*

-============================================================================

-PR_ExecuteProgram

-

-The interpretation main loop

-============================================================================

-*/

-

-/*

-====================

-PR_EnterFunction

-

-Returns the new program statement counter

-====================

-*/

-int PR_EnterFunction (dfunction_t *f)

-{

-	int		i, j, c, o;

-

-	pr_stack[pr_depth].s = pr_xstatement;

-	pr_stack[pr_depth].f = pr_xfunction;	

-	pr_depth++;

-	if (pr_depth >= MAX_STACK_DEPTH)

-		PR_RunError ("stack overflow");

-

-// save off any locals that the new function steps on

-	c = f->locals;

-	if (localstack_used + c > LOCALSTACK_SIZE)

-		PR_RunError ("PR_ExecuteProgram: locals stack overflow\n");

-

-	for (i=0 ; i < c ; i++)

-		localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];

-	localstack_used += c;

-

-// copy parameters

-	o = f->parm_start;

-	for (i=0 ; i<f->numparms ; i++)

-	{

-		for (j=0 ; j<f->parm_size[i] ; j++)

-		{

-			((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j];

-			o++;

-		}

-	}

-

-	pr_xfunction = f;

-	return f->first_statement - 1;	// offset the s++

-}

-

-/*

-====================

-PR_LeaveFunction

-====================

-*/

-int PR_LeaveFunction (void)

-{

-	int		i, c;

-

-	if (pr_depth <= 0)

-		Sys_Error ("prog stack underflow");

-

-// restore locals from the stack

-	c = pr_xfunction->locals;

-	localstack_used -= c;

-	if (localstack_used < 0)

-		PR_RunError ("PR_ExecuteProgram: locals stack underflow\n");

-

-	for (i=0 ; i < c ; i++)

-		((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];

-

-// up stack

-	pr_depth--;

-	pr_xfunction = pr_stack[pr_depth].f;

-	return pr_stack[pr_depth].s;

-}

-

-

-/*

-====================

-PR_ExecuteProgram

-====================

-*/

-void PR_ExecuteProgram (func_t fnum)

-{

-	eval_t	*a, *b, *c;

-	int			s;

-	dstatement_t	*st;

-	dfunction_t	*f, *newf;

-	int		runaway;

-	int		i;

-	edict_t	*ed;

-	int		exitdepth;

-	eval_t	*ptr;

-

-	if (!fnum || fnum >= progs->numfunctions)

-	{

-		if (pr_global_struct->self)

-			ED_Print (PROG_TO_EDICT(pr_global_struct->self));

-		Host_Error ("PR_ExecuteProgram: NULL function");

-	}

-	

-	f = &pr_functions[fnum];

-

-	runaway = 100000;

-	pr_trace = false;

-

-// make a stack frame

-	exitdepth = pr_depth;

-

-	s = PR_EnterFunction (f);

-	

-while (1)

-{

-	s++;	// next statement

-

-	st = &pr_statements[s];

-	a = (eval_t *)&pr_globals[st->a];

-	b = (eval_t *)&pr_globals[st->b];

-	c = (eval_t *)&pr_globals[st->c];

-	

-	if (!--runaway)

-		PR_RunError ("runaway loop error");

-		

-	pr_xfunction->profile++;

-	pr_xstatement = s;

-	

-	if (pr_trace)

-		PR_PrintStatement (st);

-		

-	switch (st->op)

-	{

-	case OP_ADD_F:

-		c->_float = a->_float + b->_float;

-		break;

-	case OP_ADD_V:

-		c->vector[0] = a->vector[0] + b->vector[0];

-		c->vector[1] = a->vector[1] + b->vector[1];

-		c->vector[2] = a->vector[2] + b->vector[2];

-		break;

-		

-	case OP_SUB_F:

-		c->_float = a->_float - b->_float;

-		break;

-	case OP_SUB_V:

-		c->vector[0] = a->vector[0] - b->vector[0];

-		c->vector[1] = a->vector[1] - b->vector[1];

-		c->vector[2] = a->vector[2] - b->vector[2];

-		break;

-

-	case OP_MUL_F:

-		c->_float = a->_float * b->_float;

-		break;

-	case OP_MUL_V:

-		c->_float = a->vector[0]*b->vector[0]

-				+ a->vector[1]*b->vector[1]

-				+ a->vector[2]*b->vector[2];

-		break;

-	case OP_MUL_FV:

-		c->vector[0] = a->_float * b->vector[0];

-		c->vector[1] = a->_float * b->vector[1];

-		c->vector[2] = a->_float * b->vector[2];

-		break;

-	case OP_MUL_VF:

-		c->vector[0] = b->_float * a->vector[0];

-		c->vector[1] = b->_float * a->vector[1];

-		c->vector[2] = b->_float * a->vector[2];

-		break;

-

-	case OP_DIV_F:

-		c->_float = a->_float / b->_float;

-		break;

-	

-	case OP_BITAND:

-		c->_float = (int)a->_float & (int)b->_float;

-		break;

-	

-	case OP_BITOR:

-		c->_float = (int)a->_float | (int)b->_float;

-		break;

-	

-		

-	case OP_GE:

-		c->_float = a->_float >= b->_float;

-		break;

-	case OP_LE:

-		c->_float = a->_float <= b->_float;

-		break;

-	case OP_GT:

-		c->_float = a->_float > b->_float;

-		break;

-	case OP_LT:

-		c->_float = a->_float < b->_float;

-		break;

-	case OP_AND:

-		c->_float = a->_float && b->_float;

-		break;

-	case OP_OR:

-		c->_float = a->_float || b->_float;

-		break;

-		

-	case OP_NOT_F:

-		c->_float = !a->_float;

-		break;

-	case OP_NOT_V:

-		c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2];

-		break;

-	case OP_NOT_S:

-		c->_float = !a->string || !pr_strings[a->string];

-		break;

-	case OP_NOT_FNC:

-		c->_float = !a->function;

-		break;

-	case OP_NOT_ENT:

-		c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts);

-		break;

-

-	case OP_EQ_F:

-		c->_float = a->_float == b->_float;

-		break;

-	case OP_EQ_V:

-		c->_float = (a->vector[0] == b->vector[0]) &&

-					(a->vector[1] == b->vector[1]) &&

-					(a->vector[2] == b->vector[2]);

-		break;

-	case OP_EQ_S:

-		c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string);

-		break;

-	case OP_EQ_E:

-		c->_float = a->_int == b->_int;

-		break;

-	case OP_EQ_FNC:

-		c->_float = a->function == b->function;

-		break;

-

-

-	case OP_NE_F:

-		c->_float = a->_float != b->_float;

-		break;

-	case OP_NE_V:

-		c->_float = (a->vector[0] != b->vector[0]) ||

-					(a->vector[1] != b->vector[1]) ||

-					(a->vector[2] != b->vector[2]);

-		break;

-	case OP_NE_S:

-		c->_float = strcmp(pr_strings+a->string,pr_strings+b->string);

-		break;

-	case OP_NE_E:

-		c->_float = a->_int != b->_int;

-		break;

-	case OP_NE_FNC:

-		c->_float = a->function != b->function;

-		break;

-

-//==================

-	case OP_STORE_F:

-	case OP_STORE_ENT:

-	case OP_STORE_FLD:		// integers

-	case OP_STORE_S:

-	case OP_STORE_FNC:		// pointers

-		b->_int = a->_int;

-		break;

-	case OP_STORE_V:

-		b->vector[0] = a->vector[0];

-		b->vector[1] = a->vector[1];

-		b->vector[2] = a->vector[2];

-		break;

-		

-	case OP_STOREP_F:

-	case OP_STOREP_ENT:

-	case OP_STOREP_FLD:		// integers

-	case OP_STOREP_S:

-	case OP_STOREP_FNC:		// pointers

-		ptr = (eval_t *)((byte *)sv.edicts + b->_int);

-		ptr->_int = a->_int;

-		break;

-	case OP_STOREP_V:

-		ptr = (eval_t *)((byte *)sv.edicts + b->_int);

-		ptr->vector[0] = a->vector[0];

-		ptr->vector[1] = a->vector[1];

-		ptr->vector[2] = a->vector[2];

-		break;

-		

-	case OP_ADDRESS:

-		ed = PROG_TO_EDICT(a->edict);

-#ifdef PARANOID

-		NUM_FOR_EDICT(ed);		// make sure it's in range

-#endif

-		if (ed == (edict_t *)sv.edicts && sv.state == ss_active)

-			PR_RunError ("assignment to world entity");

-		c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts;

-		break;

-		

-	case OP_LOAD_F:

-	case OP_LOAD_FLD:

-	case OP_LOAD_ENT:

-	case OP_LOAD_S:

-	case OP_LOAD_FNC:

-		ed = PROG_TO_EDICT(a->edict);

-#ifdef PARANOID

-		NUM_FOR_EDICT(ed);		// make sure it's in range

-#endif

-		a = (eval_t *)((int *)&ed->v + b->_int);

-		c->_int = a->_int;

-		break;

-

-	case OP_LOAD_V:

-		ed = PROG_TO_EDICT(a->edict);

-#ifdef PARANOID

-		NUM_FOR_EDICT(ed);		// make sure it's in range

-#endif

-		a = (eval_t *)((int *)&ed->v + b->_int);

-		c->vector[0] = a->vector[0];

-		c->vector[1] = a->vector[1];

-		c->vector[2] = a->vector[2];

-		break;

-		

-//==================

-

-	case OP_IFNOT:

-		if (!a->_int)

-			s += st->b - 1;	// offset the s++

-		break;

-		

-	case OP_IF:

-		if (a->_int)

-			s += st->b - 1;	// offset the s++

-		break;

-		

-	case OP_GOTO:

-		s += st->a - 1;	// offset the s++

-		break;

-		

-	case OP_CALL0:

-	case OP_CALL1:

-	case OP_CALL2:

-	case OP_CALL3:

-	case OP_CALL4:

-	case OP_CALL5:

-	case OP_CALL6:

-	case OP_CALL7:

-	case OP_CALL8:

-		pr_argc = st->op - OP_CALL0;

-		if (!a->function)

-			PR_RunError ("NULL function");

-

-		newf = &pr_functions[a->function];

-

-		if (newf->first_statement < 0)

-		{	// negative statements are built in functions

-			i = -newf->first_statement;

-			if (i >= pr_numbuiltins)

-				PR_RunError ("Bad builtin call number");

-			pr_builtins[i] ();

-			break;

-		}

-

-		s = PR_EnterFunction (newf);

-		break;

-

-	case OP_DONE:

-	case OP_RETURN:

-		pr_globals[OFS_RETURN] = pr_globals[st->a];

-		pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];

-		pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];

-	

-		s = PR_LeaveFunction ();

-		if (pr_depth == exitdepth)

-			return;		// all done

-		break;

-		

-	case OP_STATE:

-		ed = PROG_TO_EDICT(pr_global_struct->self);

-#ifdef FPS_20

-		ed->v.nextthink = pr_global_struct->time + 0.05;

-#else

-		ed->v.nextthink = pr_global_struct->time + 0.1;

-#endif

-		if (a->_float != ed->v.frame)

-		{

-			ed->v.frame = a->_float;

-		}

-		ed->v.think = b->function;

-		break;

-		

-	default:

-		PR_RunError ("Bad opcode %i", st->op);

-	}

-}

-

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+
+
+/*
+
+*/
+
+typedef struct
+{
+	int				s;
+	dfunction_t		*f;
+} prstack_t;
+
+#define	MAX_STACK_DEPTH		32
+prstack_t	pr_stack[MAX_STACK_DEPTH];
+int			pr_depth;
+
+#define	LOCALSTACK_SIZE		2048
+int			localstack[LOCALSTACK_SIZE];
+int			localstack_used;
+
+
+qboolean	pr_trace;
+dfunction_t	*pr_xfunction;
+int			pr_xstatement;
+
+
+int		pr_argc;
+
+const char *pr_opnames[] =
+{
+"DONE",
+
+"MUL_F",
+"MUL_V", 
+"MUL_FV",
+"MUL_VF",
+ 
+"DIV",
+
+"ADD_F",
+"ADD_V", 
+  
+"SUB_F",
+"SUB_V",
+
+"EQ_F",
+"EQ_V",
+"EQ_S", 
+"EQ_E",
+"EQ_FNC",
+ 
+"NE_F",
+"NE_V", 
+"NE_S",
+"NE_E", 
+"NE_FNC",
+ 
+"LE",
+"GE",
+"LT",
+"GT", 
+
+"INDIRECT",
+"INDIRECT",
+"INDIRECT", 
+"INDIRECT", 
+"INDIRECT",
+"INDIRECT", 
+
+"ADDRESS", 
+
+"STORE_F",
+"STORE_V",
+"STORE_S",
+"STORE_ENT",
+"STORE_FLD",
+"STORE_FNC",
+
+"STOREP_F",
+"STOREP_V",
+"STOREP_S",
+"STOREP_ENT",
+"STOREP_FLD",
+"STOREP_FNC",
+
+"RETURN",
+  
+"NOT_F",
+"NOT_V",
+"NOT_S", 
+"NOT_ENT", 
+"NOT_FNC", 
+  
+"IF",
+"IFNOT",
+  
+"CALL0",
+"CALL1",
+"CALL2",
+"CALL3",
+"CALL4",
+"CALL5",
+"CALL6",
+"CALL7",
+"CALL8",
+  
+"STATE",
+  
+"GOTO", 
+  
+"AND",
+"OR", 
+
+"BITAND",
+"BITOR"
+};
+
+char *PR_GlobalString (int ofs);
+char *PR_GlobalStringNoContents (int ofs);
+
+
+//=============================================================================
+
+/*
+=================
+PR_PrintStatement
+=================
+*/
+void PR_PrintStatement (dstatement_t *s)
+{
+	int		i;
+	
+	if ( (unsigned)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0]))
+	{
+		Con_Printf ("%s ",  pr_opnames[s->op]);
+		i = strlen(pr_opnames[s->op]);
+		for ( ; i<10 ; i++)
+			Con_Printf (" ");
+	}
+		
+	if (s->op == OP_IF || s->op == OP_IFNOT)
+		Con_Printf ("%sbranch %i",PR_GlobalString(s->a),s->b);
+	else if (s->op == OP_GOTO)
+	{
+		Con_Printf ("branch %i",s->a);
+	}
+	else if ( (unsigned)(s->op - OP_STORE_F) < 6)
+	{
+		Con_Printf ("%s",PR_GlobalString(s->a));
+		Con_Printf ("%s", PR_GlobalStringNoContents(s->b));
+	}
+	else
+	{
+		if (s->a)
+			Con_Printf ("%s",PR_GlobalString(s->a));
+		if (s->b)
+			Con_Printf ("%s",PR_GlobalString(s->b));
+		if (s->c)
+			Con_Printf ("%s", PR_GlobalStringNoContents(s->c));
+	}
+	Con_Printf ("\n");
+}
+
+/*
+============
+PR_StackTrace
+============
+*/
+void PR_StackTrace (void)
+{
+	dfunction_t	*f;
+	int			i;
+	
+	if (pr_depth == 0)
+	{
+		Con_Printf ("<NO STACK>\n");
+		return;
+	}
+	
+	pr_stack[pr_depth].f = pr_xfunction;
+	for (i=pr_depth ; i>=0 ; i--)
+	{
+		f = pr_stack[i].f;
+		
+		if (!f)
+		{
+			Con_Printf ("<NO FUNCTION>\n");
+		}
+		else
+			Con_Printf ("%12s : %s\n", pr_strings + f->s_file, pr_strings + f->s_name);		
+	}
+}
+
+
+/*
+============
+PR_Profile_f
+
+============
+*/
+void PR_Profile_f (void)
+{
+	dfunction_t	*f, *best;
+	int			max;
+	int			num;
+	int			i;
+	
+	num = 0;	
+	do
+	{
+		max = 0;
+		best = NULL;
+		for (i=0 ; i<progs->numfunctions ; i++)
+		{
+			f = &pr_functions[i];
+			if (f->profile > max)
+			{
+				max = f->profile;
+				best = f;
+			}
+		}
+		if (best)
+		{
+			if (num < 10)
+				Con_Printf ("%7i %s\n", best->profile, pr_strings+best->s_name);
+			num++;
+			best->profile = 0;
+		}
+	} while (best);
+}
+
+
+/*
+============
+PR_RunError
+
+Aborts the currently executing function
+============
+*/
+void PR_RunError (const char *error, ...)
+{
+	va_list		argptr;
+	char		string[1024];
+
+	va_start (argptr,error);
+	vsprintf (string,error,argptr);
+	va_end (argptr);
+
+	PR_PrintStatement (pr_statements + pr_xstatement);
+	PR_StackTrace ();
+	Con_Printf ("%s\n", string);
+	
+	pr_depth = 0;		// dump the stack so host_error can shutdown functions
+
+	Host_Error ("Program error");
+}
+
+/*
+============================================================================
+PR_ExecuteProgram
+
+The interpretation main loop
+============================================================================
+*/
+
+/*
+====================
+PR_EnterFunction
+
+Returns the new program statement counter
+====================
+*/
+int PR_EnterFunction (dfunction_t *f)
+{
+	int		i, j, c, o;
+
+	pr_stack[pr_depth].s = pr_xstatement;
+	pr_stack[pr_depth].f = pr_xfunction;	
+	pr_depth++;
+	if (pr_depth >= MAX_STACK_DEPTH)
+		PR_RunError ("stack overflow");
+
+// save off any locals that the new function steps on
+	c = f->locals;
+	if (localstack_used + c > LOCALSTACK_SIZE)
+		PR_RunError ("PR_ExecuteProgram: locals stack overflow\n");
+
+	for (i=0 ; i < c ; i++)
+		localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];
+	localstack_used += c;
+
+// copy parameters
+	o = f->parm_start;
+	for (i=0 ; i<f->numparms ; i++)
+	{
+		for (j=0 ; j<f->parm_size[i] ; j++)
+		{
+			((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j];
+			o++;
+		}
+	}
+
+	pr_xfunction = f;
+	return f->first_statement - 1;	// offset the s++
+}
+
+/*
+====================
+PR_LeaveFunction
+====================
+*/
+int PR_LeaveFunction (void)
+{
+	int		i, c;
+
+	if (pr_depth <= 0)
+		Sys_Error ("prog stack underflow");
+
+// restore locals from the stack
+	c = pr_xfunction->locals;
+	localstack_used -= c;
+	if (localstack_used < 0)
+		PR_RunError ("PR_ExecuteProgram: locals stack underflow\n");
+
+	for (i=0 ; i < c ; i++)
+		((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];
+
+// up stack
+	pr_depth--;
+	pr_xfunction = pr_stack[pr_depth].f;
+	return pr_stack[pr_depth].s;
+}
+
+
+/*
+====================
+PR_ExecuteProgram
+====================
+*/
+void PR_ExecuteProgram (func_t fnum)
+{
+	eval_t	*a, *b, *c;
+	int			s;
+	dstatement_t	*st;
+	dfunction_t	*f, *newf;
+	int		runaway;
+	int		i;
+	edict_t	*ed;
+	int		exitdepth;
+	eval_t	*ptr;
+
+	if (!fnum || fnum >= progs->numfunctions)
+	{
+		if (pr_global_struct->self)
+			ED_Print (PROG_TO_EDICT(pr_global_struct->self));
+		Host_Error ("PR_ExecuteProgram: NULL function");
+	}
+	
+	f = &pr_functions[fnum];
+
+	runaway = 100000;
+	pr_trace = false;
+
+// make a stack frame
+	exitdepth = pr_depth;
+
+	s = PR_EnterFunction (f);
+	
+while (1)
+{
+	s++;	// next statement
+
+	st = &pr_statements[s];
+	a = (eval_t *)&pr_globals[st->a];
+	b = (eval_t *)&pr_globals[st->b];
+	c = (eval_t *)&pr_globals[st->c];
+	
+	if (!--runaway)
+		PR_RunError ("runaway loop error");
+		
+	pr_xfunction->profile++;
+	pr_xstatement = s;
+	
+	if (pr_trace)
+		PR_PrintStatement (st);
+		
+	switch (st->op)
+	{
+	case OP_ADD_F:
+		c->_float = a->_float + b->_float;
+		break;
+	case OP_ADD_V:
+		c->vector[0] = a->vector[0] + b->vector[0];
+		c->vector[1] = a->vector[1] + b->vector[1];
+		c->vector[2] = a->vector[2] + b->vector[2];
+		break;
+		
+	case OP_SUB_F:
+		c->_float = a->_float - b->_float;
+		break;
+	case OP_SUB_V:
+		c->vector[0] = a->vector[0] - b->vector[0];
+		c->vector[1] = a->vector[1] - b->vector[1];
+		c->vector[2] = a->vector[2] - b->vector[2];
+		break;
+
+	case OP_MUL_F:
+		c->_float = a->_float * b->_float;
+		break;
+	case OP_MUL_V:
+		c->_float = a->vector[0]*b->vector[0]
+				+ a->vector[1]*b->vector[1]
+				+ a->vector[2]*b->vector[2];
+		break;
+	case OP_MUL_FV:
+		c->vector[0] = a->_float * b->vector[0];
+		c->vector[1] = a->_float * b->vector[1];
+		c->vector[2] = a->_float * b->vector[2];
+		break;
+	case OP_MUL_VF:
+		c->vector[0] = b->_float * a->vector[0];
+		c->vector[1] = b->_float * a->vector[1];
+		c->vector[2] = b->_float * a->vector[2];
+		break;
+
+	case OP_DIV_F:
+		c->_float = a->_float / b->_float;
+		break;
+	
+	case OP_BITAND:
+		c->_float = (int)a->_float & (int)b->_float;
+		break;
+	
+	case OP_BITOR:
+		c->_float = (int)a->_float | (int)b->_float;
+		break;
+	
+		
+	case OP_GE:
+		c->_float = a->_float >= b->_float;
+		break;
+	case OP_LE:
+		c->_float = a->_float <= b->_float;
+		break;
+	case OP_GT:
+		c->_float = a->_float > b->_float;
+		break;
+	case OP_LT:
+		c->_float = a->_float < b->_float;
+		break;
+	case OP_AND:
+		c->_float = a->_float && b->_float;
+		break;
+	case OP_OR:
+		c->_float = a->_float || b->_float;
+		break;
+		
+	case OP_NOT_F:
+		c->_float = !a->_float;
+		break;
+	case OP_NOT_V:
+		c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2];
+		break;
+	case OP_NOT_S:
+		c->_float = !a->string || !pr_strings[a->string];
+		break;
+	case OP_NOT_FNC:
+		c->_float = !a->function;
+		break;
+	case OP_NOT_ENT:
+		c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts);
+		break;
+
+	case OP_EQ_F:
+		c->_float = a->_float == b->_float;
+		break;
+	case OP_EQ_V:
+		c->_float = (a->vector[0] == b->vector[0]) &&
+					(a->vector[1] == b->vector[1]) &&
+					(a->vector[2] == b->vector[2]);
+		break;
+	case OP_EQ_S:
+		c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string);
+		break;
+	case OP_EQ_E:
+		c->_float = a->_int == b->_int;
+		break;
+	case OP_EQ_FNC:
+		c->_float = a->function == b->function;
+		break;
+
+
+	case OP_NE_F:
+		c->_float = a->_float != b->_float;
+		break;
+	case OP_NE_V:
+		c->_float = (a->vector[0] != b->vector[0]) ||
+					(a->vector[1] != b->vector[1]) ||
+					(a->vector[2] != b->vector[2]);
+		break;
+	case OP_NE_S:
+		c->_float = strcmp(pr_strings+a->string,pr_strings+b->string);
+		break;
+	case OP_NE_E:
+		c->_float = a->_int != b->_int;
+		break;
+	case OP_NE_FNC:
+		c->_float = a->function != b->function;
+		break;
+
+//==================
+	case OP_STORE_F:
+	case OP_STORE_ENT:
+	case OP_STORE_FLD:		// integers
+	case OP_STORE_S:
+	case OP_STORE_FNC:		// pointers
+		b->_int = a->_int;
+		break;
+	case OP_STORE_V:
+		b->vector[0] = a->vector[0];
+		b->vector[1] = a->vector[1];
+		b->vector[2] = a->vector[2];
+		break;
+		
+	case OP_STOREP_F:
+	case OP_STOREP_ENT:
+	case OP_STOREP_FLD:		// integers
+	case OP_STOREP_S:
+	case OP_STOREP_FNC:		// pointers
+		ptr = (eval_t *)((byte *)sv.edicts + b->_int);
+		ptr->_int = a->_int;
+		break;
+	case OP_STOREP_V:
+		ptr = (eval_t *)((byte *)sv.edicts + b->_int);
+		ptr->vector[0] = a->vector[0];
+		ptr->vector[1] = a->vector[1];
+		ptr->vector[2] = a->vector[2];
+		break;
+		
+	case OP_ADDRESS:
+		ed = PROG_TO_EDICT(a->edict);
+#ifdef PARANOID
+		NUM_FOR_EDICT(ed);		// make sure it's in range
+#endif
+		if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
+			PR_RunError ("assignment to world entity");
+		c->_int = (byte *)(ed->u.i + b->_int) - (byte *)sv.edicts;
+		break;
+		
+	case OP_LOAD_F:
+	case OP_LOAD_FLD:
+	case OP_LOAD_ENT:
+	case OP_LOAD_S:
+	case OP_LOAD_FNC:
+		ed = PROG_TO_EDICT(a->edict);
+#ifdef PARANOID
+		NUM_FOR_EDICT(ed);		// make sure it's in range
+#endif
+		a = (eval_t *)(ed->u.i + b->_int);
+		c->_int = a->_int;
+		break;
+
+	case OP_LOAD_V:
+		ed = PROG_TO_EDICT(a->edict);
+#ifdef PARANOID
+		NUM_FOR_EDICT(ed);		// make sure it's in range
+#endif
+		a = (eval_t *)(ed->u.i + b->_int);
+		c->vector[0] = a->vector[0];
+		c->vector[1] = a->vector[1];
+		c->vector[2] = a->vector[2];
+		break;
+		
+//==================
+
+	case OP_IFNOT:
+		if (!a->_int)
+			s += st->b - 1;	// offset the s++
+		break;
+		
+	case OP_IF:
+		if (a->_int)
+			s += st->b - 1;	// offset the s++
+		break;
+		
+	case OP_GOTO:
+		s += st->a - 1;	// offset the s++
+		break;
+		
+	case OP_CALL0:
+	case OP_CALL1:
+	case OP_CALL2:
+	case OP_CALL3:
+	case OP_CALL4:
+	case OP_CALL5:
+	case OP_CALL6:
+	case OP_CALL7:
+	case OP_CALL8:
+		pr_argc = st->op - OP_CALL0;
+		if (!a->function)
+			PR_RunError ("NULL function");
+
+		newf = &pr_functions[a->function];
+
+		if (newf->first_statement < 0)
+		{	// negative statements are built in functions
+			i = -newf->first_statement;
+			if (i >= pr_numbuiltins)
+				PR_RunError ("Bad builtin call number");
+			pr_builtins[i] ();
+			break;
+		}
+
+		s = PR_EnterFunction (newf);
+		break;
+
+	case OP_DONE:
+	case OP_RETURN:
+		pr_globals[OFS_RETURN] = pr_globals[st->a];
+		pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
+		pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
+	
+		s = PR_LeaveFunction ();
+		if (pr_depth == exitdepth)
+			return;		// all done
+		break;
+		
+	case OP_STATE:
+		ed = PROG_TO_EDICT(pr_global_struct->self);
+#ifdef FPS_20
+		ed->u.v.nextthink = pr_global_struct->time + 0.05;
+#else
+		ed->u.v.nextthink = pr_global_struct->time + 0.1;
+#endif
+		if (a->_float != ed->u.v.frame)
+		{
+			ed->u.v.frame = a->_float;
+		}
+		ed->u.v.think = b->function;
+		break;
+		
+	default:
+		PR_RunError ("Bad opcode %i", st->op);
+	}
+}
+
+}
diff --git a/quake/src/WinQuake/progs.h b/quake/src/WinQuake/progs.h
index e2a05f0..2b794b6 100644
--- a/quake/src/WinQuake/progs.h
+++ b/quake/src/WinQuake/progs.h
@@ -1,134 +1,139 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-#include "pr_comp.h"			// defs shared with qcc

-#include "progdefs.h"			// generated by program cdefs

-

-typedef union eval_s

-{

-	string_t		string;

-	float			_float;

-	float			vector[3];

-	func_t			function;

-	int				_int;

-	int				edict;

-} eval_t;	

-

-#define	MAX_ENT_LEAFS	16

-typedef struct edict_s

-{

-	qboolean	free;

-	link_t		area;				// linked to a division node or leaf

-	

-	int			num_leafs;

-	short		leafnums[MAX_ENT_LEAFS];

-

-	entity_state_t	baseline;

-	

-	float		freetime;			// sv.time when the object was freed

-	entvars_t	v;					// C exported fields from progs

-// other fields from progs come immediately after

-} edict_t;

-#define	EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)

-

-//============================================================================

-

-extern	dprograms_t		*progs;

-extern	dfunction_t		*pr_functions;

-extern	char			*pr_strings;

-extern	ddef_t			*pr_globaldefs;

-extern	ddef_t			*pr_fielddefs;

-extern	dstatement_t	*pr_statements;

-extern	globalvars_t	*pr_global_struct;

-extern	float			*pr_globals;			// same as pr_global_struct

-

-extern	int				pr_edict_size;	// in bytes

-

-//============================================================================

-

-void PR_Init (void);

-

-void PR_ExecuteProgram (func_t fnum);

-void PR_LoadProgs (void);

-

-void PR_Profile_f (void);

-

-edict_t *ED_Alloc (void);

-void ED_Free (edict_t *ed);

-

-char	*ED_NewString (char *string);

-// returns a copy of the string allocated from the server's string heap

-

-void ED_Print (edict_t *ed);

-void ED_Write (FILE *f, edict_t *ed);

-char *ED_ParseEdict (char *data, edict_t *ent);

-

-void ED_WriteGlobals (FILE *f);

-void ED_ParseGlobals (char *data);

-

-void ED_LoadFromFile (char *data);

-

-//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size))

-//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size)

-

-edict_t *EDICT_NUM(int n);

-int NUM_FOR_EDICT(edict_t *e);

-

-#define	NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size))

-

-#define	EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts)

-#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e))

-

-//============================================================================

-

-#define	G_FLOAT(o) (pr_globals[o])

-#define	G_INT(o) (*(int *)&pr_globals[o])

-#define	G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))

-#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))

-#define	G_VECTOR(o) (&pr_globals[o])

-#define	G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o])

-#define	G_FUNCTION(o) (*(func_t *)&pr_globals[o])

-

-#define	E_FLOAT(e,o) (((float*)&e->v)[o])

-#define	E_INT(e,o) (*(int *)&((float*)&e->v)[o])

-#define	E_VECTOR(e,o) (&((float*)&e->v)[o])

-#define	E_STRING(e,o) (pr_strings + *(string_t *)&((float*)&e->v)[o])

-

-extern	int		type_size[8];

-

-typedef void (*builtin_t) (void);

-extern	builtin_t *pr_builtins;

-extern int pr_numbuiltins;

-

-extern int		pr_argc;

-

-extern	qboolean	pr_trace;

-extern	dfunction_t	*pr_xfunction;

-extern	int			pr_xstatement;

-

-extern	unsigned short		pr_crc;

-

-void PR_RunError (char *error, ...);

-

-void ED_PrintEdicts (void);

-void ED_PrintNum (int ent);

-

-eval_t *GetEdictFieldValue(edict_t *ed, char *field);

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "pr_comp.h"			// defs shared with qcc
+#include "progdefs.h"			// generated by program cdefs
+
+typedef union eval_s
+{
+	string_t		string;
+	float			_float;
+	float			vector[3];
+	func_t			function;
+	int				_int;
+	int				edict;
+} eval_t;	
+
+#define	MAX_ENT_LEAFS	16
+typedef struct edict_s
+{
+	qboolean	free;
+	link_t		area;				// linked to a division node or leaf
+	
+	int			num_leafs;
+	short		leafnums[MAX_ENT_LEAFS];
+
+	entity_state_t	baseline;
+	
+	float		freetime;			// sv.time when the object was freed
+	union {
+	  entvars_t	v;					// C exported fields from progs
+	  int i[1]; // Variable length
+	  float f[1];
+	  string_t s[1];
+	} u;
+// other fields from progs come immediately after
+} edict_t;
+#define	EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
+
+//============================================================================
+
+extern	dprograms_t		*progs;
+extern	dfunction_t		*pr_functions;
+extern	char			*pr_strings;
+extern	ddef_t			*pr_globaldefs;
+extern	ddef_t			*pr_fielddefs;
+extern	dstatement_t	*pr_statements;
+extern	globalvars_t	*pr_global_struct;
+extern	float			*pr_globals;			// same as pr_global_struct
+
+extern	int				pr_edict_size;	// in bytes
+
+//============================================================================
+
+void PR_Init (void);
+
+void PR_ExecuteProgram (func_t fnum);
+void PR_LoadProgs (void);
+
+void PR_Profile_f (void);
+
+edict_t *ED_Alloc (void);
+void ED_Free (edict_t *ed);
+
+char	*ED_NewString (const char *string);
+// returns a copy of the string allocated from the server's string heap
+
+void ED_Print (edict_t *ed);
+void ED_Write (FILE *f, edict_t *ed);
+char *ED_ParseEdict (char *data, edict_t *ent);
+
+void ED_WriteGlobals (FILE *f);
+void ED_ParseGlobals (char *data);
+
+void ED_LoadFromFile (char *data);
+
+//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size))
+//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size)
+
+edict_t *EDICT_NUM(int n);
+int NUM_FOR_EDICT(edict_t *e);
+
+#define	NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size))
+
+#define	EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts)
+#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e))
+
+//============================================================================
+
+#define	G_FLOAT(o) (pr_globals[o])
+#define	G_INT(o) (*(int *)&pr_globals[o])
+#define	G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))
+#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))
+#define	G_VECTOR(o) (&pr_globals[o])
+#define	G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o])
+#define	G_FUNCTION(o) (*(func_t *)&pr_globals[o])
+
+#define	E_FLOAT(e,o) (((float*)&e->u.v)[o])
+#define	E_INT(e,o) (*(int *)&((float*)&e->u.v)[o])
+#define	E_VECTOR(e,o) (&((float*)&e->u.v)[o])
+#define	E_STRING(e,o) (pr_strings + e->u.s[o])
+
+extern	int		type_size[8];
+
+typedef void (*builtin_t) (void);
+extern	builtin_t *pr_builtins;
+extern int pr_numbuiltins;
+
+extern int		pr_argc;
+
+extern	qboolean	pr_trace;
+extern	dfunction_t	*pr_xfunction;
+extern	int			pr_xstatement;
+
+extern	unsigned short		pr_crc;
+
+void PR_RunError (const char *error, ...);
+
+void ED_PrintEdicts (void);
+void ED_PrintNum (int ent);
+
+eval_t *GetEdictFieldValue(edict_t *ed, const char *field);
+
diff --git a/quake/src/WinQuake/q.bat b/quake/src/WinQuake/q.bat
old mode 100755
new mode 100644
diff --git a/quake/src/WinQuake/qa.bat b/quake/src/WinQuake/qa.bat
old mode 100755
new mode 100644
diff --git a/quake/src/WinQuake/qb.bat b/quake/src/WinQuake/qb.bat
old mode 100755
new mode 100644
diff --git a/quake/src/WinQuake/qt.bat b/quake/src/WinQuake/qt.bat
old mode 100755
new mode 100644
diff --git a/quake/src/WinQuake/quakedef.h b/quake/src/WinQuake/quakedef.h
index d0aabaf..f9ec795 100644
--- a/quake/src/WinQuake/quakedef.h
+++ b/quake/src/WinQuake/quakedef.h
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // quakedef.h -- primary header for client
 
 //#define	GLTEST			// experimental stuff
@@ -32,6 +32,10 @@
 
 //define	PARANOID			// speed sapping error checking
 
+#define GLQUAKE
+#define USE_OPENGLES
+#define id386 0
+
 #ifdef QUAKE2
 #define	GAMENAME	"id1"		// directory to look in by default
 #else
@@ -61,11 +65,13 @@
 
 #endif
 
+#if !defined id386
 #if defined __i386__ // && !defined __sun__
 #define id386	1
 #else
 #define id386	0
 #endif
+#endif
 
 #if id386
 #define UNALIGNED_OK	1	// set to 0 if unaligned accesses are not supported
@@ -270,10 +276,10 @@
 
 typedef struct
 {
-	char	*basedir;
-	char	*cachedir;		// for development over ISDN lines
+	const char	*basedir;
+	const char	*cachedir;		// for development over ISDN lines
 	int		argc;
-	char	**argv;
+	const char	**argv;
 	void	*membase;
 	int		memsize;
 } quakeparms_t;
@@ -308,11 +314,11 @@
 void Host_InitCommands (void);
 void Host_Init (quakeparms_t *parms);
 void Host_Shutdown(void);
-void Host_Error (char *error, ...);
-void Host_EndGame (char *message, ...);
+void Host_Error (const char *error, ...);
+void Host_EndGame (const char *message, ...);
 void Host_Frame (float time);
 void Host_Quit_f (void);
-void Host_ClientCommands (char *fmt, ...);
+void Host_ClientCommands (const char *fmt, ...);
 void Host_ShutdownServer (qboolean crash);
 
 extern qboolean		msg_suppress_1;		// suppresses resolution and cache size console output
@@ -333,3 +339,118 @@
 void Chase_Init (void);
 void Chase_Reset (void);
 void Chase_Update (void);
+
+qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace);
+
+// Linux versions of msdos CRT functions
+#define stricmp strcasecmp
+
+// Helper functions for OpenGL ES
+void DrawQuad_NoTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+void DrawQuad(GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat u, GLfloat v, GLfloat uw, GLfloat vh);
+
+void shadowLoadIdentity( GLfloat* m);
+void shadowRotatef( GLfloat* m, GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+void shadowTranslatef( GLfloat* m, GLfloat x, GLfloat y, GLfloat z);
+
+#ifdef USE_OPENGLES
+// Reimplementation of OpenGL functions that are missing in OpenGL ES
+
+#define GL_INTENSITY				0x8049
+
+void glColor3f(GLfloat r, GLfloat g, GLfloat b);
+void glColor4fv(GLfloat* pColor);
+
+#define VERTEXARRAYSIZE 2048
+
+extern float gVertexBuffer[VERTEXARRAYSIZE];
+extern float gColorBuffer[VERTEXARRAYSIZE];
+extern float gTexCoordBuffer[VERTEXARRAYSIZE];
+
+#endif // USE_OPENGLES
+
+void glTexImage2DHelper( GLenum target,
+	 GLint level,
+	 GLint internalformat,
+	 GLsizei width,
+	 GLsizei height,
+	 GLint border,
+	 GLenum format,
+	 GLenum type,
+	 const GLvoid *pixels );
+
+// Forward declarations:
+
+qboolean VID_Is8bit(void);
+void GL_SubdivideSurface (msurface_t *fa);
+void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr);
+int R_LightPoint (vec3_t p);
+void R_DrawBrushModel (entity_t *e);
+void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
+void R_AnimateLight (void);
+void V_CalcBlend (void);
+void R_DrawWorld (void);
+void R_RenderDlights(void);
+void R_DrawParticles (void);
+void R_DrawWaterSurfaces (void);
+void R_RenderBrushPoly (msurface_t *fa);
+void R_InitParticles (void);
+void GL_Upload8_EXT (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
+void R_ClearParticles (void);
+void GL_BuildLightmaps (void);
+void EmitWaterPolys (msurface_t *fa);
+void EmitSkyPolys (msurface_t *fa);
+void EmitBothSkyLayers (msurface_t *fa);
+void R_DrawSkyChain (msurface_t *s);
+qboolean R_CullBox (vec3_t mins, vec3_t maxs);
+void R_MarkLights (dlight_t *light, int bit, mnode_t *node);
+void R_RotateForEntity (entity_t *e);
+void R_StoreEfrags (efrag_t **ppefrag);
+void GL_Set2D (void);
+
+// Poor Man's Profiler
+// (And general loging.)
+
+void PMP_Begin(const char* fmt,...);
+void PMP_Event(const char* fmt,...);
+void PMP_End(const char* fmt,...);
+
+#define PMPLOG(ARGS) PMP_Event ARGS
+#define PMPWARNING(ARGS) PMP_Event ARGS
+#define PMPERROR(ARGS) PMP_Event ARGS
+
+// #define ENABLE_PMP
+
+#ifdef ENABLE_PMP
+
+#define PMPBEGIN(ARGS) PMP_Begin ARGS
+#define PMPEVENT(ARGS) PMP_Event ARGS
+#define PMPEND(ARGS) PMP_End ARGS
+
+#else
+
+#define PMPBEGIN(ARGS) ((void) 0)
+#define PMPEVENT(ARGS) ((void) 0)
+#define PMPEND(ARGS) ((void) 0)
+
+#endif
+
+// Measure fastest / slowest frames
+typedef struct frameTime_ {
+    int frame;
+	float time;
+} frameTime;
+
+extern frameTime fastestFrame;
+extern frameTime slowestFrame;
+
+void InitFrameTimes();
+
+// Feature configuration
+
+#define SUPPORT_8BIT_MIPMAPGENERATION
+
+#ifdef SUPPORT_8BIT_MIPMAPGENERATION
+extern unsigned char d_15to8table[65536];
+#endif // SUPPORT_8BIT_MIPMAPGENERATION
+
diff --git a/quake/src/WinQuake/r_aclip.c b/quake/src/WinQuake/r_aclip.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_aclip.c
rename to quake/src/WinQuake/r_aclip.cpp
diff --git a/quake/src/WinQuake/r_alias.c b/quake/src/WinQuake/r_alias.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_alias.c
rename to quake/src/WinQuake/r_alias.cpp
diff --git a/quake/src/WinQuake/r_bsp.c b/quake/src/WinQuake/r_bsp.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_bsp.c
rename to quake/src/WinQuake/r_bsp.cpp
diff --git a/quake/src/WinQuake/r_draw.c b/quake/src/WinQuake/r_draw.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_draw.c
rename to quake/src/WinQuake/r_draw.cpp
diff --git a/quake/src/WinQuake/r_edge.c b/quake/src/WinQuake/r_edge.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_edge.c
rename to quake/src/WinQuake/r_edge.cpp
diff --git a/quake/src/WinQuake/r_efrag.c b/quake/src/WinQuake/r_efrag.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_efrag.c
rename to quake/src/WinQuake/r_efrag.cpp
diff --git a/quake/src/WinQuake/r_light.c b/quake/src/WinQuake/r_light.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_light.c
rename to quake/src/WinQuake/r_light.cpp
diff --git a/quake/src/WinQuake/r_local.h b/quake/src/WinQuake/r_local.h
index 779acce..cc352dd 100644
--- a/quake/src/WinQuake/r_local.h
+++ b/quake/src/WinQuake/r_local.h
@@ -313,4 +313,4 @@
 void R_SplitEntityOnNode2 (mnode_t *node);

 void R_MarkLights (dlight_t *light, int bit, mnode_t *node);

 

-#endif
\ No newline at end of file
+#endif

diff --git a/quake/src/WinQuake/r_main.c b/quake/src/WinQuake/r_main.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_main.c
rename to quake/src/WinQuake/r_main.cpp
diff --git a/quake/src/WinQuake/r_misc.c b/quake/src/WinQuake/r_misc.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_misc.c
rename to quake/src/WinQuake/r_misc.cpp
diff --git a/quake/src/WinQuake/r_part.c b/quake/src/WinQuake/r_part.cpp
old mode 100644
new mode 100755
similarity index 89%
rename from quake/src/WinQuake/r_part.c
rename to quake/src/WinQuake/r_part.cpp
index 5586440..3688c81
--- a/quake/src/WinQuake/r_part.c
+++ b/quake/src/WinQuake/r_part.cpp
@@ -1,800 +1,863 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-

-#include "quakedef.h"

-#include "r_local.h"

-

-#define MAX_PARTICLES			2048	// default max # of particles at one

-										//  time

-#define ABSOLUTE_MIN_PARTICLES	512		// no fewer than this no matter what's

-										//  on the command line

-

-int		ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};

-int		ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};

-int		ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};

-

-particle_t	*active_particles, *free_particles;

-

-particle_t	*particles;

-int			r_numparticles;

-

-vec3_t			r_pright, r_pup, r_ppn;

-

-

-/*

-===============

-R_InitParticles

-===============

-*/

-void R_InitParticles (void)

-{

-	int		i;

-

-	i = COM_CheckParm ("-particles");

-

-	if (i)

-	{

-		r_numparticles = (int)(Q_atoi(com_argv[i+1]));

-		if (r_numparticles < ABSOLUTE_MIN_PARTICLES)

-			r_numparticles = ABSOLUTE_MIN_PARTICLES;

-	}

-	else

-	{

-		r_numparticles = MAX_PARTICLES;

-	}

-

-	particles = (particle_t *)

-			Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");

-}

-

-#ifdef QUAKE2

-void R_DarkFieldParticles (entity_t *ent)

-{

-	int			i, j, k;

-	particle_t	*p;

-	float		vel;

-	vec3_t		dir;

-	vec3_t		org;

-

-	org[0] = ent->origin[0];

-	org[1] = ent->origin[1];

-	org[2] = ent->origin[2];

-	for (i=-16 ; i<16 ; i+=8)

-		for (j=-16 ; j<16 ; j+=8)

-			for (k=0 ; k<32 ; k+=8)

-			{

-				if (!free_particles)

-					return;

-				p = free_particles;

-				free_particles = p->next;

-				p->next = active_particles;

-				active_particles = p;

-		

-				p->die = cl.time + 0.2 + (rand()&7) * 0.02;

-				p->color = 150 + rand()%6;

-				p->type = pt_slowgrav;

-				

-				dir[0] = j*8;

-				dir[1] = i*8;

-				dir[2] = k*8;

-	

-				p->org[0] = org[0] + i + (rand()&3);

-				p->org[1] = org[1] + j + (rand()&3);

-				p->org[2] = org[2] + k + (rand()&3);

-	

-				VectorNormalize (dir);						

-				vel = 50 + (rand()&63);

-				VectorScale (dir, vel, p->vel);

-			}

-}

-#endif

-

-

-/*

-===============

-R_EntityParticles

-===============

-*/

-

-#define NUMVERTEXNORMALS	162

-extern	float	r_avertexnormals[NUMVERTEXNORMALS][3];

-vec3_t	avelocities[NUMVERTEXNORMALS];

-float	beamlength = 16;

-vec3_t	avelocity = {23, 7, 3};

-float	partstep = 0.01;

-float	timescale = 0.01;

-

-void R_EntityParticles (entity_t *ent)

-{

-	int			count;

-	int			i;

-	particle_t	*p;

-	float		angle;

-	float		sr, sp, sy, cr, cp, cy;

-	vec3_t		forward;

-	float		dist;

-	

-	dist = 64;

-	count = 50;

-

-if (!avelocities[0][0])

-{

-for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)

-avelocities[0][i] = (rand()&255) * 0.01;

-}

-

-

-	for (i=0 ; i<NUMVERTEXNORMALS ; i++)

-	{

-		angle = cl.time * avelocities[i][0];

-		sy = sin(angle);

-		cy = cos(angle);

-		angle = cl.time * avelocities[i][1];

-		sp = sin(angle);

-		cp = cos(angle);

-		angle = cl.time * avelocities[i][2];

-		sr = sin(angle);

-		cr = cos(angle);

-	

-		forward[0] = cp*cy;

-		forward[1] = cp*sy;

-		forward[2] = -sp;

-

-		if (!free_particles)

-			return;

-		p = free_particles;

-		free_particles = p->next;

-		p->next = active_particles;

-		active_particles = p;

-

-		p->die = cl.time + 0.01;

-		p->color = 0x6f;

-		p->type = pt_explode;

-		

-		p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;			

-		p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;			

-		p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;			

-	}

-}

-

-

-/*

-===============

-R_ClearParticles

-===============

-*/

-void R_ClearParticles (void)

-{

-	int		i;

-	

-	free_particles = &particles[0];

-	active_particles = NULL;

-

-	for (i=0 ;i<r_numparticles ; i++)

-		particles[i].next = &particles[i+1];

-	particles[r_numparticles-1].next = NULL;

-}

-

-

-void R_ReadPointFile_f (void)

-{

-	FILE	*f;

-	vec3_t	org;

-	int		r;

-	int		c;

-	particle_t	*p;

-	char	name[MAX_OSPATH];

-	

-	sprintf (name,"maps/%s.pts", sv.name);

-

-	COM_FOpenFile (name, &f);

-	if (!f)

-	{

-		Con_Printf ("couldn't open %s\n", name);

-		return;

-	}

-	

-	Con_Printf ("Reading %s...\n", name);

-	c = 0;

-	for ( ;; )

-	{

-		r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);

-		if (r != 3)

-			break;

-		c++;

-		

-		if (!free_particles)

-		{

-			Con_Printf ("Not enough free particles\n");

-			break;

-		}

-		p = free_particles;

-		free_particles = p->next;

-		p->next = active_particles;

-		active_particles = p;

-		

-		p->die = 99999;

-		p->color = (-c)&15;

-		p->type = pt_static;

-		VectorCopy (vec3_origin, p->vel);

-		VectorCopy (org, p->org);

-	}

-

-	fclose (f);

-	Con_Printf ("%i points read\n", c);

-}

-

-/*

-===============

-R_ParseParticleEffect

-

-Parse an effect out of the server message

-===============

-*/

-void R_ParseParticleEffect (void)

-{

-	vec3_t		org, dir;

-	int			i, count, msgcount, color;

-	

-	for (i=0 ; i<3 ; i++)

-		org[i] = MSG_ReadCoord ();

-	for (i=0 ; i<3 ; i++)

-		dir[i] = MSG_ReadChar () * (1.0/16);

-	msgcount = MSG_ReadByte ();

-	color = MSG_ReadByte ();

-

-if (msgcount == 255)

-	count = 1024;

-else

-	count = msgcount;

-	

-	R_RunParticleEffect (org, dir, color, count);

-}

-	

-/*

-===============

-R_ParticleExplosion

-

-===============

-*/

-void R_ParticleExplosion (vec3_t org)

-{

-	int			i, j;

-	particle_t	*p;

-	

-	for (i=0 ; i<1024 ; i++)

-	{

-		if (!free_particles)

-			return;

-		p = free_particles;

-		free_particles = p->next;

-		p->next = active_particles;

-		active_particles = p;

-

-		p->die = cl.time + 5;

-		p->color = ramp1[0];

-		p->ramp = rand()&3;

-		if (i & 1)

-		{

-			p->type = pt_explode;

-			for (j=0 ; j<3 ; j++)

-			{

-				p->org[j] = org[j] + ((rand()%32)-16);

-				p->vel[j] = (rand()%512)-256;

-			}

-		}

-		else

-		{

-			p->type = pt_explode2;

-			for (j=0 ; j<3 ; j++)

-			{

-				p->org[j] = org[j] + ((rand()%32)-16);

-				p->vel[j] = (rand()%512)-256;

-			}

-		}

-	}

-}

-

-/*

-===============

-R_ParticleExplosion2

-

-===============

-*/

-void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)

-{

-	int			i, j;

-	particle_t	*p;

-	int			colorMod = 0;

-

-	for (i=0; i<512; i++)

-	{

-		if (!free_particles)

-			return;

-		p = free_particles;

-		free_particles = p->next;

-		p->next = active_particles;

-		active_particles = p;

-

-		p->die = cl.time + 0.3;

-		p->color = colorStart + (colorMod % colorLength);

-		colorMod++;

-

-		p->type = pt_blob;

-		for (j=0 ; j<3 ; j++)

-		{

-			p->org[j] = org[j] + ((rand()%32)-16);

-			p->vel[j] = (rand()%512)-256;

-		}

-	}

-}

-

-/*

-===============

-R_BlobExplosion

-

-===============

-*/

-void R_BlobExplosion (vec3_t org)

-{

-	int			i, j;

-	particle_t	*p;

-	

-	for (i=0 ; i<1024 ; i++)

-	{

-		if (!free_particles)

-			return;

-		p = free_particles;

-		free_particles = p->next;

-		p->next = active_particles;

-		active_particles = p;

-

-		p->die = cl.time + 1 + (rand()&8)*0.05;

-

-		if (i & 1)

-		{

-			p->type = pt_blob;

-			p->color = 66 + rand()%6;

-			for (j=0 ; j<3 ; j++)

-			{

-				p->org[j] = org[j] + ((rand()%32)-16);

-				p->vel[j] = (rand()%512)-256;

-			}

-		}

-		else

-		{

-			p->type = pt_blob2;

-			p->color = 150 + rand()%6;

-			for (j=0 ; j<3 ; j++)

-			{

-				p->org[j] = org[j] + ((rand()%32)-16);

-				p->vel[j] = (rand()%512)-256;

-			}

-		}

-	}

-}

-

-/*

-===============

-R_RunParticleEffect

-

-===============

-*/

-void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)

-{

-	int			i, j;

-	particle_t	*p;

-	

-	for (i=0 ; i<count ; i++)

-	{

-		if (!free_particles)

-			return;

-		p = free_particles;

-		free_particles = p->next;

-		p->next = active_particles;

-		active_particles = p;

-

-		if (count == 1024)

-		{	// rocket explosion

-			p->die = cl.time + 5;

-			p->color = ramp1[0];

-			p->ramp = rand()&3;

-			if (i & 1)

-			{

-				p->type = pt_explode;

-				for (j=0 ; j<3 ; j++)

-				{

-					p->org[j] = org[j] + ((rand()%32)-16);

-					p->vel[j] = (rand()%512)-256;

-				}

-			}

-			else

-			{

-				p->type = pt_explode2;

-				for (j=0 ; j<3 ; j++)

-				{

-					p->org[j] = org[j] + ((rand()%32)-16);

-					p->vel[j] = (rand()%512)-256;

-				}

-			}

-		}

-		else

-		{

-			p->die = cl.time + 0.1*(rand()%5);

-			p->color = (color&~7) + (rand()&7);

-			p->type = pt_slowgrav;

-			for (j=0 ; j<3 ; j++)

-			{

-				p->org[j] = org[j] + ((rand()&15)-8);

-				p->vel[j] = dir[j]*15;// + (rand()%300)-150;

-			}

-		}

-	}

-}

-

-

-/*

-===============

-R_LavaSplash

-

-===============

-*/

-void R_LavaSplash (vec3_t org)

-{

-	int			i, j, k;

-	particle_t	*p;

-	float		vel;

-	vec3_t		dir;

-

-	for (i=-16 ; i<16 ; i++)

-		for (j=-16 ; j<16 ; j++)

-			for (k=0 ; k<1 ; k++)

-			{

-				if (!free_particles)

-					return;

-				p = free_particles;

-				free_particles = p->next;

-				p->next = active_particles;

-				active_particles = p;

-		

-				p->die = cl.time + 2 + (rand()&31) * 0.02;

-				p->color = 224 + (rand()&7);

-				p->type = pt_slowgrav;

-				

-				dir[0] = j*8 + (rand()&7);

-				dir[1] = i*8 + (rand()&7);

-				dir[2] = 256;

-	

-				p->org[0] = org[0] + dir[0];

-				p->org[1] = org[1] + dir[1];

-				p->org[2] = org[2] + (rand()&63);

-	

-				VectorNormalize (dir);						

-				vel = 50 + (rand()&63);

-				VectorScale (dir, vel, p->vel);

-			}

-}

-

-/*

-===============

-R_TeleportSplash

-

-===============

-*/

-void R_TeleportSplash (vec3_t org)

-{

-	int			i, j, k;

-	particle_t	*p;

-	float		vel;

-	vec3_t		dir;

-

-	for (i=-16 ; i<16 ; i+=4)

-		for (j=-16 ; j<16 ; j+=4)

-			for (k=-24 ; k<32 ; k+=4)

-			{

-				if (!free_particles)

-					return;

-				p = free_particles;

-				free_particles = p->next;

-				p->next = active_particles;

-				active_particles = p;

-		

-				p->die = cl.time + 0.2 + (rand()&7) * 0.02;

-				p->color = 7 + (rand()&7);

-				p->type = pt_slowgrav;

-				

-				dir[0] = j*8;

-				dir[1] = i*8;

-				dir[2] = k*8;

-	

-				p->org[0] = org[0] + i + (rand()&3);

-				p->org[1] = org[1] + j + (rand()&3);

-				p->org[2] = org[2] + k + (rand()&3);

-	

-				VectorNormalize (dir);						

-				vel = 50 + (rand()&63);

-				VectorScale (dir, vel, p->vel);

-			}

-}

-

-void R_RocketTrail (vec3_t start, vec3_t end, int type)

-{

-	vec3_t		vec;

-	float		len;

-	int			j;

-	particle_t	*p;

-	int			dec;

-	static int	tracercount;

-

-	VectorSubtract (end, start, vec);

-	len = VectorNormalize (vec);

-	if (type < 128)

-		dec = 3;

-	else

-	{

-		dec = 1;

-		type -= 128;

-	}

-

-	while (len > 0)

-	{

-		len -= dec;

-

-		if (!free_particles)

-			return;

-		p = free_particles;

-		free_particles = p->next;

-		p->next = active_particles;

-		active_particles = p;

-		

-		VectorCopy (vec3_origin, p->vel);

-		p->die = cl.time + 2;

-

-		switch (type)

-		{

-			case 0:	// rocket trail

-				p->ramp = (rand()&3);

-				p->color = ramp3[(int)p->ramp];

-				p->type = pt_fire;

-				for (j=0 ; j<3 ; j++)

-					p->org[j] = start[j] + ((rand()%6)-3);

-				break;

-

-			case 1:	// smoke smoke

-				p->ramp = (rand()&3) + 2;

-				p->color = ramp3[(int)p->ramp];

-				p->type = pt_fire;

-				for (j=0 ; j<3 ; j++)

-					p->org[j] = start[j] + ((rand()%6)-3);

-				break;

-

-			case 2:	// blood

-				p->type = pt_grav;

-				p->color = 67 + (rand()&3);

-				for (j=0 ; j<3 ; j++)

-					p->org[j] = start[j] + ((rand()%6)-3);

-				break;

-

-			case 3:

-			case 5:	// tracer

-				p->die = cl.time + 0.5;

-				p->type = pt_static;

-				if (type == 3)

-					p->color = 52 + ((tracercount&4)<<1);

-				else

-					p->color = 230 + ((tracercount&4)<<1);

-			

-				tracercount++;

-

-				VectorCopy (start, p->org);

-				if (tracercount & 1)

-				{

-					p->vel[0] = 30*vec[1];

-					p->vel[1] = 30*-vec[0];

-				}

-				else

-				{

-					p->vel[0] = 30*-vec[1];

-					p->vel[1] = 30*vec[0];

-				}

-				break;

-

-			case 4:	// slight blood

-				p->type = pt_grav;

-				p->color = 67 + (rand()&3);

-				for (j=0 ; j<3 ; j++)

-					p->org[j] = start[j] + ((rand()%6)-3);

-				len -= 3;

-				break;

-

-			case 6:	// voor trail

-				p->color = 9*16 + 8 + (rand()&3);

-				p->type = pt_static;

-				p->die = cl.time + 0.3;

-				for (j=0 ; j<3 ; j++)

-					p->org[j] = start[j] + ((rand()&15)-8);

-				break;

-		}

-		

-

-		VectorAdd (start, vec, start);

-	}

-}

-

-

-/*

-===============

-R_DrawParticles

-===============

-*/

-extern	cvar_t	sv_gravity;

-

-void R_DrawParticles (void)

-{

-	particle_t		*p, *kill;

-	float			grav;

-	int				i;

-	float			time2, time3;

-	float			time1;

-	float			dvel;

-	float			frametime;

-	

-#ifdef GLQUAKE

-	vec3_t			up, right;

-	float			scale;

-

-    GL_Bind(particletexture);

-	glEnable (GL_BLEND);

-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

-	glBegin (GL_TRIANGLES);

-

-	VectorScale (vup, 1.5, up);

-	VectorScale (vright, 1.5, right);

-#else

-	D_StartParticles ();

-

-	VectorScale (vright, xscaleshrink, r_pright);

-	VectorScale (vup, yscaleshrink, r_pup);

-	VectorCopy (vpn, r_ppn);

-#endif

-	frametime = cl.time - cl.oldtime;

-	time3 = frametime * 15;

-	time2 = frametime * 10; // 15;

-	time1 = frametime * 5;

-	grav = frametime * sv_gravity.value * 0.05;

-	dvel = 4*frametime;

-	

-	for ( ;; ) 

-	{

-		kill = active_particles;

-		if (kill && kill->die < cl.time)

-		{

-			active_particles = kill->next;

-			kill->next = free_particles;

-			free_particles = kill;

-			continue;

-		}

-		break;

-	}

-

-	for (p=active_particles ; p ; p=p->next)

-	{

-		for ( ;; )

-		{

-			kill = p->next;

-			if (kill && kill->die < cl.time)

-			{

-				p->next = kill->next;

-				kill->next = free_particles;

-				free_particles = kill;

-				continue;

-			}

-			break;

-		}

-

-#ifdef GLQUAKE

-		// hack a scale up to keep particles from disapearing

-		scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]

-			+ (p->org[2] - r_origin[2])*vpn[2];

-		if (scale < 20)

-			scale = 1;

-		else

-			scale = 1 + scale * 0.004;

-		glColor3ubv ((byte *)&d_8to24table[(int)p->color]);

-		glTexCoord2f (0,0);

-		glVertex3fv (p->org);

-		glTexCoord2f (1,0);

-		glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);

-		glTexCoord2f (0,1);

-		glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);

-#else

-		D_DrawParticle (p);

-#endif

-		p->org[0] += p->vel[0]*frametime;

-		p->org[1] += p->vel[1]*frametime;

-		p->org[2] += p->vel[2]*frametime;

-		

-		switch (p->type)

-		{

-		case pt_static:

-			break;

-		case pt_fire:

-			p->ramp += time1;

-			if (p->ramp >= 6)

-				p->die = -1;

-			else

-				p->color = ramp3[(int)p->ramp];

-			p->vel[2] += grav;

-			break;

-

-		case pt_explode:

-			p->ramp += time2;

-			if (p->ramp >=8)

-				p->die = -1;

-			else

-				p->color = ramp1[(int)p->ramp];

-			for (i=0 ; i<3 ; i++)

-				p->vel[i] += p->vel[i]*dvel;

-			p->vel[2] -= grav;

-			break;

-

-		case pt_explode2:

-			p->ramp += time3;

-			if (p->ramp >=8)

-				p->die = -1;

-			else

-				p->color = ramp2[(int)p->ramp];

-			for (i=0 ; i<3 ; i++)

-				p->vel[i] -= p->vel[i]*frametime;

-			p->vel[2] -= grav;

-			break;

-

-		case pt_blob:

-			for (i=0 ; i<3 ; i++)

-				p->vel[i] += p->vel[i]*dvel;

-			p->vel[2] -= grav;

-			break;

-

-		case pt_blob2:

-			for (i=0 ; i<2 ; i++)

-				p->vel[i] -= p->vel[i]*dvel;

-			p->vel[2] -= grav;

-			break;

-

-		case pt_grav:

-#ifdef QUAKE2

-			p->vel[2] -= grav * 20;

-			break;

-#endif

-		case pt_slowgrav:

-			p->vel[2] -= grav;

-			break;

-		}

-	}

-

-#ifdef GLQUAKE

-	glEnd ();

-	glDisable (GL_BLEND);

-	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

-#else

-	D_EndParticles ();

-#endif

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+#include "r_local.h"
+
+#define MAX_PARTICLES			2048	// default max # of particles at one
+										//  time
+#define ABSOLUTE_MIN_PARTICLES	512		// no fewer than this no matter what's
+										//  on the command line
+
+int		ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
+int		ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
+int		ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
+
+particle_t	*active_particles, *free_particles;
+
+particle_t	*particles;
+int			r_numparticles;
+
+vec3_t			r_pright, r_pup, r_ppn;
+
+
+/*
+===============
+R_InitParticles
+===============
+*/
+void R_InitParticles (void)
+{
+	int		i;
+
+	i = COM_CheckParm ("-particles");
+
+	if (i)
+	{
+		r_numparticles = (int)(Q_atoi(com_argv[i+1]));
+		if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
+			r_numparticles = ABSOLUTE_MIN_PARTICLES;
+	}
+	else
+	{
+		r_numparticles = MAX_PARTICLES;
+	}
+
+	particles = (particle_t *)
+			Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
+}
+
+#ifdef QUAKE2
+void R_DarkFieldParticles (entity_t *ent)
+{
+	int			i, j, k;
+	particle_t	*p;
+	float		vel;
+	vec3_t		dir;
+	vec3_t		org;
+
+	org[0] = ent->origin[0];
+	org[1] = ent->origin[1];
+	org[2] = ent->origin[2];
+	for (i=-16 ; i<16 ; i+=8)
+		for (j=-16 ; j<16 ; j+=8)
+			for (k=0 ; k<32 ; k+=8)
+			{
+				if (!free_particles)
+					return;
+				p = free_particles;
+				free_particles = p->next;
+				p->next = active_particles;
+				active_particles = p;
+		
+				p->die = cl.time + 0.2 + (rand()&7) * 0.02;
+				p->color = 150 + rand()%6;
+				p->type = pt_slowgrav;
+				
+				dir[0] = j*8;
+				dir[1] = i*8;
+				dir[2] = k*8;
+	
+				p->org[0] = org[0] + i + (rand()&3);
+				p->org[1] = org[1] + j + (rand()&3);
+				p->org[2] = org[2] + k + (rand()&3);
+	
+				VectorNormalize (dir);						
+				vel = 50 + (rand()&63);
+				VectorScale (dir, vel, p->vel);
+			}
+}
+#endif
+
+
+/*
+===============
+R_EntityParticles
+===============
+*/
+
+#define NUMVERTEXNORMALS	162
+extern	float	r_avertexnormals[NUMVERTEXNORMALS][3];
+vec3_t	avelocities[NUMVERTEXNORMALS];
+float	beamlength = 16;
+vec3_t	avelocity = {23, 7, 3};
+float	partstep = 0.01;
+float	timescale = 0.01;
+
+void R_EntityParticles (entity_t *ent)
+{
+	int			count;
+	int			i;
+	particle_t	*p;
+	float		angle;
+	float		sr, sp, sy, cr, cp, cy;
+	vec3_t		forward;
+	float		dist;
+	
+	dist = 64;
+	count = 50;
+
+if (!avelocities[0][0])
+{
+for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+avelocities[0][i] = (rand()&255) * 0.01;
+}
+
+
+	for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+	{
+		angle = cl.time * avelocities[i][0];
+		sy = sin(angle);
+		cy = cos(angle);
+		angle = cl.time * avelocities[i][1];
+		sp = sin(angle);
+		cp = cos(angle);
+		angle = cl.time * avelocities[i][2];
+		sr = sin(angle);
+		cr = cos(angle);
+	
+		forward[0] = cp*cy;
+		forward[1] = cp*sy;
+		forward[2] = -sp;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->die = cl.time + 0.01;
+		p->color = 0x6f;
+		p->type = pt_explode;
+		
+		p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;			
+		p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;			
+		p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;			
+	}
+}
+
+
+/*
+===============
+R_ClearParticles
+===============
+*/
+void R_ClearParticles (void)
+{
+	int		i;
+	
+	free_particles = &particles[0];
+	active_particles = NULL;
+
+	for (i=0 ;i<r_numparticles ; i++)
+		particles[i].next = &particles[i+1];
+	particles[r_numparticles-1].next = NULL;
+}
+
+
+void R_ReadPointFile_f (void)
+{
+	FILE	*f;
+	vec3_t	org;
+	int		r;
+	int		c;
+	particle_t	*p;
+	char	name[MAX_OSPATH];
+	
+	sprintf (name,"maps/%s.pts", sv.name);
+
+	COM_FOpenFile (name, &f);
+	if (!f)
+	{
+		Con_Printf ("couldn't open %s\n", name);
+		return;
+	}
+	
+	Con_Printf ("Reading %s...\n", name);
+	c = 0;
+	for ( ;; )
+	{
+		r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
+		if (r != 3)
+			break;
+		c++;
+		
+		if (!free_particles)
+		{
+			Con_Printf ("Not enough free particles\n");
+			break;
+		}
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		p->die = 99999;
+		p->color = (-c)&15;
+		p->type = pt_static;
+		VectorCopy (vec3_origin, p->vel);
+		VectorCopy (org, p->org);
+	}
+
+	fclose (f);
+	Con_Printf ("%i points read\n", c);
+}
+
+/*
+===============
+R_ParseParticleEffect
+
+Parse an effect out of the server message
+===============
+*/
+void R_ParseParticleEffect (void)
+{
+	vec3_t		org, dir;
+	int			i, count, msgcount, color;
+	
+	for (i=0 ; i<3 ; i++)
+		org[i] = MSG_ReadCoord ();
+	for (i=0 ; i<3 ; i++)
+		dir[i] = MSG_ReadChar () * (1.0/16);
+	msgcount = MSG_ReadByte ();
+	color = MSG_ReadByte ();
+
+if (msgcount == 255)
+	count = 1024;
+else
+	count = msgcount;
+	
+	R_RunParticleEffect (org, dir, color, count);
+}
+	
+/*
+===============
+R_ParticleExplosion
+
+===============
+*/
+void R_ParticleExplosion (vec3_t org)
+{
+	int			i, j;
+	particle_t	*p;
+	
+	for (i=0 ; i<1024 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->die = cl.time + 5;
+		p->color = ramp1[0];
+		p->ramp = rand()&3;
+		if (i & 1)
+		{
+			p->type = pt_explode;
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = org[j] + ((rand()%32)-16);
+				p->vel[j] = (rand()%512)-256;
+			}
+		}
+		else
+		{
+			p->type = pt_explode2;
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = org[j] + ((rand()%32)-16);
+				p->vel[j] = (rand()%512)-256;
+			}
+		}
+	}
+}
+
+/*
+===============
+R_ParticleExplosion2
+
+===============
+*/
+void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
+{
+	int			i, j;
+	particle_t	*p;
+	int			colorMod = 0;
+
+	for (i=0; i<512; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->die = cl.time + 0.3;
+		p->color = colorStart + (colorMod % colorLength);
+		colorMod++;
+
+		p->type = pt_blob;
+		for (j=0 ; j<3 ; j++)
+		{
+			p->org[j] = org[j] + ((rand()%32)-16);
+			p->vel[j] = (rand()%512)-256;
+		}
+	}
+}
+
+/*
+===============
+R_BlobExplosion
+
+===============
+*/
+void R_BlobExplosion (vec3_t org)
+{
+	int			i, j;
+	particle_t	*p;
+	
+	for (i=0 ; i<1024 ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		p->die = cl.time + 1 + (rand()&8)*0.05;
+
+		if (i & 1)
+		{
+			p->type = pt_blob;
+			p->color = 66 + rand()%6;
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = org[j] + ((rand()%32)-16);
+				p->vel[j] = (rand()%512)-256;
+			}
+		}
+		else
+		{
+			p->type = pt_blob2;
+			p->color = 150 + rand()%6;
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = org[j] + ((rand()%32)-16);
+				p->vel[j] = (rand()%512)-256;
+			}
+		}
+	}
+}
+
+/*
+===============
+R_RunParticleEffect
+
+===============
+*/
+void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
+{
+	int			i, j;
+	particle_t	*p;
+	
+	for (i=0 ; i<count ; i++)
+	{
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+
+		if (count == 1024)
+		{	// rocket explosion
+			p->die = cl.time + 5;
+			p->color = ramp1[0];
+			p->ramp = rand()&3;
+			if (i & 1)
+			{
+				p->type = pt_explode;
+				for (j=0 ; j<3 ; j++)
+				{
+					p->org[j] = org[j] + ((rand()%32)-16);
+					p->vel[j] = (rand()%512)-256;
+				}
+			}
+			else
+			{
+				p->type = pt_explode2;
+				for (j=0 ; j<3 ; j++)
+				{
+					p->org[j] = org[j] + ((rand()%32)-16);
+					p->vel[j] = (rand()%512)-256;
+				}
+			}
+		}
+		else
+		{
+			p->die = cl.time + 0.1*(rand()%5);
+			p->color = (color&~7) + (rand()&7);
+			p->type = pt_slowgrav;
+			for (j=0 ; j<3 ; j++)
+			{
+				p->org[j] = org[j] + ((rand()&15)-8);
+				p->vel[j] = dir[j]*15;// + (rand()%300)-150;
+			}
+		}
+	}
+}
+
+
+/*
+===============
+R_LavaSplash
+
+===============
+*/
+void R_LavaSplash (vec3_t org)
+{
+	int			i, j, k;
+	particle_t	*p;
+	float		vel;
+	vec3_t		dir;
+
+	for (i=-16 ; i<16 ; i++)
+		for (j=-16 ; j<16 ; j++)
+			for (k=0 ; k<1 ; k++)
+			{
+				if (!free_particles)
+					return;
+				p = free_particles;
+				free_particles = p->next;
+				p->next = active_particles;
+				active_particles = p;
+		
+				p->die = cl.time + 2 + (rand()&31) * 0.02;
+				p->color = 224 + (rand()&7);
+				p->type = pt_slowgrav;
+				
+				dir[0] = j*8 + (rand()&7);
+				dir[1] = i*8 + (rand()&7);
+				dir[2] = 256;
+	
+				p->org[0] = org[0] + dir[0];
+				p->org[1] = org[1] + dir[1];
+				p->org[2] = org[2] + (rand()&63);
+	
+				VectorNormalize (dir);						
+				vel = 50 + (rand()&63);
+				VectorScale (dir, vel, p->vel);
+			}
+}
+
+/*
+===============
+R_TeleportSplash
+
+===============
+*/
+void R_TeleportSplash (vec3_t org)
+{
+	int			i, j, k;
+	particle_t	*p;
+	float		vel;
+	vec3_t		dir;
+
+	for (i=-16 ; i<16 ; i+=4)
+		for (j=-16 ; j<16 ; j+=4)
+			for (k=-24 ; k<32 ; k+=4)
+			{
+				if (!free_particles)
+					return;
+				p = free_particles;
+				free_particles = p->next;
+				p->next = active_particles;
+				active_particles = p;
+		
+				p->die = cl.time + 0.2 + (rand()&7) * 0.02;
+				p->color = 7 + (rand()&7);
+				p->type = pt_slowgrav;
+				
+				dir[0] = j*8;
+				dir[1] = i*8;
+				dir[2] = k*8;
+	
+				p->org[0] = org[0] + i + (rand()&3);
+				p->org[1] = org[1] + j + (rand()&3);
+				p->org[2] = org[2] + k + (rand()&3);
+	
+				VectorNormalize (dir);						
+				vel = 50 + (rand()&63);
+				VectorScale (dir, vel, p->vel);
+			}
+}
+
+void R_RocketTrail (vec3_t start, vec3_t end, int type)
+{
+	vec3_t		vec;
+	float		len;
+	int			j;
+	particle_t	*p;
+	int			dec;
+	static int	tracercount;
+
+	VectorSubtract (end, start, vec);
+	len = VectorNormalize (vec);
+	if (type < 128)
+		dec = 3;
+	else
+	{
+		dec = 1;
+		type -= 128;
+	}
+
+	while (len > 0)
+	{
+		len -= dec;
+
+		if (!free_particles)
+			return;
+		p = free_particles;
+		free_particles = p->next;
+		p->next = active_particles;
+		active_particles = p;
+		
+		VectorCopy (vec3_origin, p->vel);
+		p->die = cl.time + 2;
+
+		switch (type)
+		{
+			case 0:	// rocket trail
+				p->ramp = (rand()&3);
+				p->color = ramp3[(int)p->ramp];
+				p->type = pt_fire;
+				for (j=0 ; j<3 ; j++)
+					p->org[j] = start[j] + ((rand()%6)-3);
+				break;
+
+			case 1:	// smoke smoke
+				p->ramp = (rand()&3) + 2;
+				p->color = ramp3[(int)p->ramp];
+				p->type = pt_fire;
+				for (j=0 ; j<3 ; j++)
+					p->org[j] = start[j] + ((rand()%6)-3);
+				break;
+
+			case 2:	// blood
+				p->type = pt_grav;
+				p->color = 67 + (rand()&3);
+				for (j=0 ; j<3 ; j++)
+					p->org[j] = start[j] + ((rand()%6)-3);
+				break;
+
+			case 3:
+			case 5:	// tracer
+				p->die = cl.time + 0.5;
+				p->type = pt_static;
+				if (type == 3)
+					p->color = 52 + ((tracercount&4)<<1);
+				else
+					p->color = 230 + ((tracercount&4)<<1);
+			
+				tracercount++;
+
+				VectorCopy (start, p->org);
+				if (tracercount & 1)
+				{
+					p->vel[0] = 30*vec[1];
+					p->vel[1] = 30*-vec[0];
+				}
+				else
+				{
+					p->vel[0] = 30*-vec[1];
+					p->vel[1] = 30*vec[0];
+				}
+				break;
+
+			case 4:	// slight blood
+				p->type = pt_grav;
+				p->color = 67 + (rand()&3);
+				for (j=0 ; j<3 ; j++)
+					p->org[j] = start[j] + ((rand()%6)-3);
+				len -= 3;
+				break;
+
+			case 6:	// voor trail
+				p->color = 9*16 + 8 + (rand()&3);
+				p->type = pt_static;
+				p->die = cl.time + 0.3;
+				for (j=0 ; j<3 ; j++)
+					p->org[j] = start[j] + ((rand()&15)-8);
+				break;
+		}
+		
+
+		VectorAdd (start, vec, start);
+	}
+}
+
+
+/*
+===============
+R_DrawParticles
+===============
+*/
+extern	cvar_t	sv_gravity;
+
+void R_DrawParticles (void)
+{
+	particle_t		*p, *kill;
+	float			grav;
+	int				i;
+	float			time2, time3;
+	float			time1;
+	float			dvel;
+	float			frametime;
+#ifdef USE_OPENGLES
+	float*			pPos = gVertexBuffer;
+	unsigned char*	pColor = (unsigned char*) gColorBuffer;
+	unsigned char*  pUV = (unsigned char*) gTexCoordBuffer;
+	int				particleIndex = 0;
+	int				maxParticleIndex = (int) sizeof(gVertexBuffer) / (sizeof(float) * 3) - 3;
+#endif
+#ifdef GLQUAKE
+	vec3_t			up, right;
+	float			scale;
+
+    GL_Bind(particletexture);
+
+	glEnable (GL_BLEND);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	
+#ifdef USE_OPENGLES
+	glEnableClientState(GL_COLOR_ARRAY);
+    glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
+	glTexCoordPointer(2, GL_BYTE, 0, gTexCoordBuffer);
+	glColorPointer(3, GL_UNSIGNED_BYTE, 0, gColorBuffer);
+	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+#else
+	glBegin (GL_TRIANGLES);
+#endif
+
+	VectorScale (vup, 1.5, up);
+	VectorScale (vright, 1.5, right);
+#else
+	D_StartParticles ();
+
+	VectorScale (vright, xscaleshrink, r_pright);
+	VectorScale (vup, yscaleshrink, r_pup);
+	VectorCopy (vpn, r_ppn);
+#endif
+	frametime = cl.time - cl.oldtime;
+	time3 = frametime * 15;
+	time2 = frametime * 10; // 15;
+	time1 = frametime * 5;
+	grav = frametime * sv_gravity.value * 0.05;
+	dvel = 4*frametime;
+	
+	for ( ;; ) 
+	{
+		kill = active_particles;
+		if (kill && kill->die < cl.time)
+		{
+			active_particles = kill->next;
+			kill->next = free_particles;
+			free_particles = kill;
+			continue;
+		}
+		break;
+	}
+
+	for (p=active_particles ; p ; p=p->next)
+	{
+		for ( ;; )
+		{
+			kill = p->next;
+			if (kill && kill->die < cl.time)
+			{
+				p->next = kill->next;
+				kill->next = free_particles;
+				free_particles = kill;
+				continue;
+			}
+			break;
+		}
+
+#ifdef GLQUAKE
+		// hack a scale up to keep particles from disapearing
+		scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
+			+ (p->org[2] - r_origin[2])*vpn[2];
+		if (scale < 20)
+			scale = 1;
+		else
+			scale = 1 + scale * 0.004;
+#ifdef USE_OPENGLES
+
+		if(particleIndex >= maxParticleIndex)
+		{
+			glDrawArrays(GL_TRIANGLES, 0, particleIndex);
+			particleIndex = 0;
+			pPos = gVertexBuffer;
+			pColor = (unsigned char*) gColorBuffer;
+			pUV = (unsigned char*) gTexCoordBuffer;
+		}
+		
+		memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
+		pColor += 3;
+		*pUV++ = 0;
+		*pUV++ = 0;
+		*pPos++ = p->org[0];
+		*pPos++ = p->org[1];
+		*pPos++ = p->org[2];
+
+		memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
+		pColor += 3;
+		*pUV++ = 255;
+		*pUV++ = 0;
+		*pPos++ = p->org[0] + up[0]*scale;
+		*pPos++ = p->org[1] + up[1]*scale;
+		*pPos++ = p->org[2] + up[2]*scale;
+
+		memcpy(pColor, (byte *)&d_8to24table[(int)p->color], 3);
+		pColor += 3;
+		*pUV++ = 0;
+		*pUV++ = 255;
+		*pPos++ = p->org[0] + right[0]*scale;
+		*pPos++ = p->org[1] + right[1]*scale;
+		*pPos++ = p->org[2] + right[2]*scale;
+		
+		particleIndex += 3;
+		
+#else
+		glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
+		glTexCoord2f (0,0);
+		glVertex3fv (p->org);
+		glTexCoord2f (1,0);
+		glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
+		glTexCoord2f (0,1);
+		glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
+#endif // !USE_OPENGLES
+#else
+		D_DrawParticle (p);
+#endif
+		p->org[0] += p->vel[0]*frametime;
+		p->org[1] += p->vel[1]*frametime;
+		p->org[2] += p->vel[2]*frametime;
+		
+		switch (p->type)
+		{
+		case pt_static:
+			break;
+		case pt_fire:
+			p->ramp += time1;
+			if (p->ramp >= 6)
+				p->die = -1;
+			else
+				p->color = ramp3[(int)p->ramp];
+			p->vel[2] += grav;
+			break;
+
+		case pt_explode:
+			p->ramp += time2;
+			if (p->ramp >=8)
+				p->die = -1;
+			else
+				p->color = ramp1[(int)p->ramp];
+			for (i=0 ; i<3 ; i++)
+				p->vel[i] += p->vel[i]*dvel;
+			p->vel[2] -= grav;
+			break;
+
+		case pt_explode2:
+			p->ramp += time3;
+			if (p->ramp >=8)
+				p->die = -1;
+			else
+				p->color = ramp2[(int)p->ramp];
+			for (i=0 ; i<3 ; i++)
+				p->vel[i] -= p->vel[i]*frametime;
+			p->vel[2] -= grav;
+			break;
+
+		case pt_blob:
+			for (i=0 ; i<3 ; i++)
+				p->vel[i] += p->vel[i]*dvel;
+			p->vel[2] -= grav;
+			break;
+
+		case pt_blob2:
+			for (i=0 ; i<2 ; i++)
+				p->vel[i] -= p->vel[i]*dvel;
+			p->vel[2] -= grav;
+			break;
+
+		case pt_grav:
+#ifdef QUAKE2
+			p->vel[2] -= grav * 20;
+			break;
+#endif
+		case pt_slowgrav:
+			p->vel[2] -= grav;
+			break;
+	    default:
+	        break;
+		}
+	}
+
+#ifdef GLQUAKE
+#ifdef USE_OPENGLES
+	glDrawArrays(GL_TRIANGLES, 0, particleIndex); 
+	glDisableClientState(GL_COLOR_ARRAY);
+	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+#else
+	glEnd ();
+#endif
+	glDisable (GL_BLEND);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+#else
+	D_EndParticles ();
+#endif
+}
+
diff --git a/quake/src/WinQuake/r_sky.c b/quake/src/WinQuake/r_sky.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_sky.c
rename to quake/src/WinQuake/r_sky.cpp
diff --git a/quake/src/WinQuake/r_sprite.c b/quake/src/WinQuake/r_sprite.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_sprite.c
rename to quake/src/WinQuake/r_sprite.cpp
diff --git a/quake/src/WinQuake/r_surf.c b/quake/src/WinQuake/r_surf.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_surf.c
rename to quake/src/WinQuake/r_surf.cpp
diff --git a/quake/src/WinQuake/r_vars.c b/quake/src/WinQuake/r_vars.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/r_vars.c
rename to quake/src/WinQuake/r_vars.cpp
diff --git a/quake/src/WinQuake/sbar.c b/quake/src/WinQuake/sbar.cpp
old mode 100644
new mode 100755
similarity index 98%
rename from quake/src/WinQuake/sbar.c
rename to quake/src/WinQuake/sbar.cpp
index db98cb0..b8d3994
--- a/quake/src/WinQuake/sbar.c
+++ b/quake/src/WinQuake/sbar.cpp
@@ -1,22 +1,22 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
 // sbar.c -- status bar code
 
 #include "quakedef.h"
@@ -467,8 +467,8 @@
 	Sbar_DrawString (8, 12, str);
 
 // time
-	minutes = cl.time / 60;
-	seconds = cl.time - 60*minutes;
+	minutes = (int)(cl.time / 60);
+	seconds = (int)(cl.time - 60*minutes);
 	tens = seconds / 10;
 	units = seconds - 10*tens;
 	sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
@@ -927,10 +927,14 @@
 {
 	if (scr_con_current == vid.height)
 		return;		// console is full screen
-
+	
+#if 0
 	if (sb_updates >= vid.numpages)
 		return;
-
+#else
+	// Always draw status bar, to handle hardware that always destroys
+	// the frame buffer. (essentially an infinite number of vid pages.)
+#endif
 	scr_copyeverything = 1;
 
 	sb_updates++;
@@ -1206,7 +1210,7 @@
             i = 0;
 
 	x = 324;
-	for (/* */; i < scoreboardlines && y < vid.height - 8 ; i++)
+	for (/* */; i < scoreboardlines && y < (int) (vid.height - 8) ; i++)
 	{
 		k = fragsort[i];
 		s = &cl.scores[k];
diff --git a/quake/src/WinQuake/scitech/INCLUDE/DEBUG.H b/quake/src/WinQuake/scitech/INCLUDE/DEBUG.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/scitech/INCLUDE/MGLDOS.H b/quake/src/WinQuake/scitech/INCLUDE/MGLDOS.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/scitech/INCLUDE/MGLWIN.H b/quake/src/WinQuake/scitech/INCLUDE/MGLWIN.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/scitech/INCLUDE/MGRAPH.H b/quake/src/WinQuake/scitech/INCLUDE/MGRAPH.H
old mode 100644
new mode 100755
diff --git a/quake/src/WinQuake/scitech/LIB/WIN32/VC/MGLLT.LIB b/quake/src/WinQuake/scitech/LIB/WIN32/VC/MGLLT.LIB
old mode 100644
new mode 100755
Binary files differ
diff --git a/quake/src/WinQuake/screen.c b/quake/src/WinQuake/screen.cpp
old mode 100644
new mode 100755
similarity index 99%
rename from quake/src/WinQuake/screen.c
rename to quake/src/WinQuake/screen.cpp
index dd425c3..89701ed
--- a/quake/src/WinQuake/screen.c
+++ b/quake/src/WinQuake/screen.cpp
@@ -1,991 +1,991 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// screen.c -- master for refresh, status bar, console, chat, notify, etc

-

-#include "quakedef.h"

-#include "r_local.h"

-

-// only the refresh window will be updated unless these variables are flagged 

-int			scr_copytop;

-int			scr_copyeverything;

-

-float		scr_con_current;

-float		scr_conlines;		// lines of console to display

-

-float		oldscreensize, oldfov;

-cvar_t		scr_viewsize = {"viewsize","100", true};

-cvar_t		scr_fov = {"fov","90"};	// 10 - 170

-cvar_t		scr_conspeed = {"scr_conspeed","300"};

-cvar_t		scr_centertime = {"scr_centertime","2"};

-cvar_t		scr_showram = {"showram","1"};

-cvar_t		scr_showturtle = {"showturtle","0"};

-cvar_t		scr_showpause = {"showpause","1"};

-cvar_t		scr_printspeed = {"scr_printspeed","8"};

-

-qboolean	scr_initialized;		// ready to draw

-

-qpic_t		*scr_ram;

-qpic_t		*scr_net;

-qpic_t		*scr_turtle;

-

-int			scr_fullupdate;

-

-int			clearconsole;

-int			clearnotify;

-

-viddef_t	vid;				// global video state

-

-vrect_t		*pconupdate;

-vrect_t		scr_vrect;

-

-qboolean	scr_disabled_for_loading;

-qboolean	scr_drawloading;

-float		scr_disabled_time;

-qboolean	scr_skipupdate;

-

-qboolean	block_drawing;

-

-void SCR_ScreenShot_f (void);

-

-/*

-===============================================================================

-

-CENTER PRINTING

-

-===============================================================================

-*/

-

-char		scr_centerstring[1024];

-float		scr_centertime_start;	// for slow victory printing

-float		scr_centertime_off;

-int			scr_center_lines;

-int			scr_erase_lines;

-int			scr_erase_center;

-

-/*

-==============

-SCR_CenterPrint

-

-Called for important messages that should stay in the center of the screen

-for a few moments

-==============

-*/

-void SCR_CenterPrint (char *str)

-{

-	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);

-	scr_centertime_off = scr_centertime.value;

-	scr_centertime_start = cl.time;

-

-// count the number of lines for centering

-	scr_center_lines = 1;

-	while (*str)

-	{

-		if (*str == '\n')

-			scr_center_lines++;

-		str++;

-	}

-}

-

-void SCR_EraseCenterString (void)

-{

-	int		y;

-

-	if (scr_erase_center++ > vid.numpages)

-	{

-		scr_erase_lines = 0;

-		return;

-	}

-

-	if (scr_center_lines <= 4)

-		y = vid.height*0.35;

-	else

-		y = 48;

-

-	scr_copytop = 1;

-	Draw_TileClear (0, y,vid.width, 8*scr_erase_lines);

-}

-

-void SCR_DrawCenterString (void)

-{

-	char	*start;

-	int		l;

-	int		j;

-	int		x, y;

-	int		remaining;

-

-// the finale prints the characters one at a time

-	if (cl.intermission)

-		remaining = scr_printspeed.value * (cl.time - scr_centertime_start);

-	else

-		remaining = 9999;

-

-	scr_erase_center = 0;

-	start = scr_centerstring;

-

-	if (scr_center_lines <= 4)

-		y = vid.height*0.35;

-	else

-		y = 48;

-

-	do	

-	{

-	// scan the width of the line

-		for (l=0 ; l<40 ; l++)

-			if (start[l] == '\n' || !start[l])

-				break;

-		x = (vid.width - l*8)/2;

-		for (j=0 ; j<l ; j++, x+=8)

-		{

-			Draw_Character (x, y, start[j]);	

-			if (!remaining--)

-				return;

-		}

-			

-		y += 8;

-

-		while (*start && *start != '\n')

-			start++;

-

-		if (!*start)

-			break;

-		start++;		// skip the \n

-	} while (1);

-}

-

-void SCR_CheckDrawCenterString (void)

-{

-	scr_copytop = 1;

-	if (scr_center_lines > scr_erase_lines)

-		scr_erase_lines = scr_center_lines;

-

-	scr_centertime_off -= host_frametime;

-	

-	if (scr_centertime_off <= 0 && !cl.intermission)

-		return;

-	if (key_dest != key_game)

-		return;

-

-	SCR_DrawCenterString ();

-}

-

-//=============================================================================

-

-/*

-====================

-CalcFov

-====================

-*/

-float CalcFov (float fov_x, float width, float height)

-{

-        float   a;

-        float   x;

-

-        if (fov_x < 1 || fov_x > 179)

-                Sys_Error ("Bad fov: %f", fov_x);

-

-        x = width/tan(fov_x/360*M_PI);

-

-        a = atan (height/x);

-

-        a = a*360/M_PI;

-

-        return a;

-}

-

-/*

-=================

-SCR_CalcRefdef

-

-Must be called whenever vid changes

-Internal use only

-=================

-*/

-static void SCR_CalcRefdef (void)

-{

-	vrect_t		vrect;

-	float		size;

-

-	scr_fullupdate = 0;		// force a background redraw

-	vid.recalc_refdef = 0;

-

-// force the status bar to redraw

-	Sbar_Changed ();

-

-//========================================

-	

-// bound viewsize

-	if (scr_viewsize.value < 30)

-		Cvar_Set ("viewsize","30");

-	if (scr_viewsize.value > 120)

-		Cvar_Set ("viewsize","120");

-

-// bound field of view

-	if (scr_fov.value < 10)

-		Cvar_Set ("fov","10");

-	if (scr_fov.value > 170)

-		Cvar_Set ("fov","170");

-

-	r_refdef.fov_x = scr_fov.value;

-	r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);

-

-// intermission is always full screen	

-	if (cl.intermission)

-		size = 120;

-	else

-		size = scr_viewsize.value;

-

-	if (size >= 120)

-		sb_lines = 0;		// no status bar at all

-	else if (size >= 110)

-		sb_lines = 24;		// no inventory

-	else

-		sb_lines = 24+16+8;

-

-// these calculations mirror those in R_Init() for r_refdef, but take no

-// account of water warping

-	vrect.x = 0;

-	vrect.y = 0;

-	vrect.width = vid.width;

-	vrect.height = vid.height;

-

-	R_SetVrect (&vrect, &scr_vrect, sb_lines);

-

-// guard against going from one mode to another that's less than half the

-// vertical resolution

-	if (scr_con_current > vid.height)

-		scr_con_current = vid.height;

-

-// notify the refresh of the change

-	R_ViewChanged (&vrect, sb_lines, vid.aspect);

-}

-

-

-/*

-=================

-SCR_SizeUp_f

-

-Keybinding command

-=================

-*/

-void SCR_SizeUp_f (void)

-{

-	Cvar_SetValue ("viewsize",scr_viewsize.value+10);

-	vid.recalc_refdef = 1;

-}

-

-

-/*

-=================

-SCR_SizeDown_f

-

-Keybinding command

-=================

-*/

-void SCR_SizeDown_f (void)

-{

-	Cvar_SetValue ("viewsize",scr_viewsize.value-10);

-	vid.recalc_refdef = 1;

-}

-

-//============================================================================

-

-/*

-==================

-SCR_Init

-==================

-*/

-void SCR_Init (void)

-{

-	Cvar_RegisterVariable (&scr_fov);

-	Cvar_RegisterVariable (&scr_viewsize);

-	Cvar_RegisterVariable (&scr_conspeed);

-	Cvar_RegisterVariable (&scr_showram);

-	Cvar_RegisterVariable (&scr_showturtle);

-	Cvar_RegisterVariable (&scr_showpause);

-	Cvar_RegisterVariable (&scr_centertime);

-	Cvar_RegisterVariable (&scr_printspeed);

-

-//

-// register our commands

-//

-	Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);

-	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);

-	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);

-

-	scr_ram = Draw_PicFromWad ("ram");

-	scr_net = Draw_PicFromWad ("net");

-	scr_turtle = Draw_PicFromWad ("turtle");

-

-	scr_initialized = true;

-}

-

-

-

-/*

-==============

-SCR_DrawRam

-==============

-*/

-void SCR_DrawRam (void)

-{

-	if (!scr_showram.value)

-		return;

-

-	if (!r_cache_thrash)

-		return;

-

-	Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);

-}

-

-/*

-==============

-SCR_DrawTurtle

-==============

-*/

-void SCR_DrawTurtle (void)

-{

-	static int	count;

-	

-	if (!scr_showturtle.value)

-		return;

-

-	if (host_frametime < 0.1)

-	{

-		count = 0;

-		return;

-	}

-

-	count++;

-	if (count < 3)

-		return;

-

-	Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);

-}

-

-/*

-==============

-SCR_DrawNet

-==============

-*/

-void SCR_DrawNet (void)

-{

-	if (realtime - cl.last_received_message < 0.3)

-		return;

-	if (cls.demoplayback)

-		return;

-

-	Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);

-}

-

-/*

-==============

-DrawPause

-==============

-*/

-void SCR_DrawPause (void)

-{

-	qpic_t	*pic;

-

-	if (!scr_showpause.value)		// turn off for screenshots

-		return;

-

-	if (!cl.paused)

-		return;

-

-	pic = Draw_CachePic ("gfx/pause.lmp");

-	Draw_Pic ( (vid.width - pic->width)/2, 

-		(vid.height - 48 - pic->height)/2, pic);

-}

-

-

-

-/*

-==============

-SCR_DrawLoading

-==============

-*/

-void SCR_DrawLoading (void)

-{

-	qpic_t	*pic;

-

-	if (!scr_drawloading)

-		return;

-		

-	pic = Draw_CachePic ("gfx/loading.lmp");

-	Draw_Pic ( (vid.width - pic->width)/2, 

-		(vid.height - 48 - pic->height)/2, pic);

-}

-

-

-

-//=============================================================================

-

-

-/*

-==================

-SCR_SetUpToDrawConsole

-==================

-*/

-void SCR_SetUpToDrawConsole (void)

-{

-	Con_CheckResize ();

-	

-	if (scr_drawloading)

-		return;		// never a console with loading plaque

-		

-// decide on the height of the console

-	con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;

-

-	if (con_forcedup)

-	{

-		scr_conlines = vid.height;		// full screen

-		scr_con_current = scr_conlines;

-	}

-	else if (key_dest == key_console)

-		scr_conlines = vid.height/2;	// half screen

-	else

-		scr_conlines = 0;				// none visible

-	

-	if (scr_conlines < scr_con_current)

-	{

-		scr_con_current -= scr_conspeed.value*host_frametime;

-		if (scr_conlines > scr_con_current)

-			scr_con_current = scr_conlines;

-

-	}

-	else if (scr_conlines > scr_con_current)

-	{

-		scr_con_current += scr_conspeed.value*host_frametime;

-		if (scr_conlines < scr_con_current)

-			scr_con_current = scr_conlines;

-	}

-

-	if (clearconsole++ < vid.numpages)

-	{

-		scr_copytop = 1;

-		Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current);

-		Sbar_Changed ();

-	}

-	else if (clearnotify++ < vid.numpages)

-	{

-		scr_copytop = 1;

-		Draw_TileClear (0,0,vid.width, con_notifylines);

-	}

-	else

-		con_notifylines = 0;

-}

-	

-/*

-==================

-SCR_DrawConsole

-==================

-*/

-void SCR_DrawConsole (void)

-{

-	if (scr_con_current)

-	{

-		scr_copyeverything = 1;

-		Con_DrawConsole (scr_con_current, true);

-		clearconsole = 0;

-	}

-	else

-	{

-		if (key_dest == key_game || key_dest == key_message)

-			Con_DrawNotify ();	// only draw notify in game

-	}

-}

-

-

-/* 

-============================================================================== 

- 

-						SCREEN SHOTS 

- 

-============================================================================== 

-*/ 

- 

-

-typedef struct

-{

-    char	manufacturer;

-    char	version;

-    char	encoding;

-    char	bits_per_pixel;

-    unsigned short	xmin,ymin,xmax,ymax;

-    unsigned short	hres,vres;

-    unsigned char	palette[48];

-    char	reserved;

-    char	color_planes;

-    unsigned short	bytes_per_line;

-    unsigned short	palette_type;

-    char	filler[58];

-    unsigned char	data;			// unbounded

-} pcx_t;

-

-/* 

-============== 

-WritePCXfile 

-============== 

-*/ 

-void WritePCXfile (char *filename, byte *data, int width, int height,

-	int rowbytes, byte *palette) 

-{

-	int		i, j, length;

-	pcx_t	*pcx;

-	byte		*pack;

-	  

-	pcx = Hunk_TempAlloc (width*height*2+1000);

-	if (pcx == NULL)

-	{

-		Con_Printf("SCR_ScreenShot_f: not enough memory\n");

-		return;

-	} 

- 

-	pcx->manufacturer = 0x0a;	// PCX id

-	pcx->version = 5;			// 256 color

- 	pcx->encoding = 1;		// uncompressed

-	pcx->bits_per_pixel = 8;		// 256 color

-	pcx->xmin = 0;

-	pcx->ymin = 0;

-	pcx->xmax = LittleShort((short)(width-1));

-	pcx->ymax = LittleShort((short)(height-1));

-	pcx->hres = LittleShort((short)width);

-	pcx->vres = LittleShort((short)height);

-	Q_memset (pcx->palette,0,sizeof(pcx->palette));

-	pcx->color_planes = 1;		// chunky image

-	pcx->bytes_per_line = LittleShort((short)width);

-	pcx->palette_type = LittleShort(2);		// not a grey scale

-	Q_memset (pcx->filler,0,sizeof(pcx->filler));

-

-// pack the image

-	pack = &pcx->data;

-	

-	for (i=0 ; i<height ; i++)

-	{

-		for (j=0 ; j<width ; j++)

-		{

-			if ( (*data & 0xc0) != 0xc0)

-				*pack++ = *data++;

-			else

-			{

-				*pack++ = 0xc1;

-				*pack++ = *data++;

-			}

-		}

-

-		data += rowbytes - width;

-	}

-			

-// write the palette

-	*pack++ = 0x0c;	// palette ID byte

-	for (i=0 ; i<768 ; i++)

-		*pack++ = *palette++;

-		

-// write output file 

-	length = pack - (byte *)pcx;

-	COM_WriteFile (filename, pcx, length);

-} 

- 

-

-

-/* 

-================== 

-SCR_ScreenShot_f

-================== 

-*/  

-void SCR_ScreenShot_f (void) 

-{ 

-	int     i; 

-	char		pcxname[80]; 

-	char		checkname[MAX_OSPATH];

-

-// 

-// find a file name to save it to 

-// 

-	strcpy(pcxname,"quake00.pcx");

-		

-	for (i=0 ; i<=99 ; i++) 

-	{ 

-		pcxname[5] = i/10 + '0'; 

-		pcxname[6] = i%10 + '0'; 

-		sprintf (checkname, "%s/%s", com_gamedir, pcxname);

-		if (Sys_FileTime(checkname) == -1)

-			break;	// file doesn't exist

-	} 

-	if (i==100) 

-	{

-		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n"); 

-		return;

- 	}

-

-// 

-// save the pcx file 

-// 

-	D_EnableBackBufferAccess ();	// enable direct drawing of console to back

-									//  buffer

-

-	WritePCXfile (pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes,

-				  host_basepal);

-

-	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in

-									//  for linear writes all the time

-

-	Con_Printf ("Wrote %s\n", pcxname);

-} 

-

-

-//=============================================================================

-

-

-/*

-===============

-SCR_BeginLoadingPlaque

-

-================

-*/

-void SCR_BeginLoadingPlaque (void)

-{

-	S_StopAllSounds (true);

-

-	if (cls.state != ca_connected)

-		return;

-	if (cls.signon != SIGNONS)

-		return;

-	

-// redraw with no console and the loading plaque

-	Con_ClearNotify ();

-	scr_centertime_off = 0;

-	scr_con_current = 0;

-

-	scr_drawloading = true;

-	scr_fullupdate = 0;

-	Sbar_Changed ();

-	SCR_UpdateScreen ();

-	scr_drawloading = false;

-

-	scr_disabled_for_loading = true;

-	scr_disabled_time = realtime;

-	scr_fullupdate = 0;

-}

-

-/*

-===============

-SCR_EndLoadingPlaque

-

-================

-*/

-void SCR_EndLoadingPlaque (void)

-{

-	scr_disabled_for_loading = false;

-	scr_fullupdate = 0;

-	Con_ClearNotify ();

-}

-

-//=============================================================================

-

-char	*scr_notifystring;

-qboolean	scr_drawdialog;

-

-void SCR_DrawNotifyString (void)

-{

-	char	*start;

-	int		l;

-	int		j;

-	int		x, y;

-

-	start = scr_notifystring;

-

-	y = vid.height*0.35;

-

-	do	

-	{

-	// scan the width of the line

-		for (l=0 ; l<40 ; l++)

-			if (start[l] == '\n' || !start[l])

-				break;

-		x = (vid.width - l*8)/2;

-		for (j=0 ; j<l ; j++, x+=8)

-			Draw_Character (x, y, start[j]);	

-			

-		y += 8;

-

-		while (*start && *start != '\n')

-			start++;

-

-		if (!*start)

-			break;

-		start++;		// skip the \n

-	} while (1);

-}

-

-/*

-==================

-SCR_ModalMessage

-

-Displays a text string in the center of the screen and waits for a Y or N

-keypress.  

-==================

-*/

-int SCR_ModalMessage (char *text)

-{

-	if (cls.state == ca_dedicated)

-		return true;

-

-	scr_notifystring = text;

- 

-// draw a fresh screen

-	scr_fullupdate = 0;

-	scr_drawdialog = true;

-	SCR_UpdateScreen ();

-	scr_drawdialog = false;

-	

-	S_ClearBuffer ();		// so dma doesn't loop current sound

-

-	do

-	{

-		key_count = -1;		// wait for a key down and up

-		Sys_SendKeyEvents ();

-	} while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);

-

-	scr_fullupdate = 0;

-	SCR_UpdateScreen ();

-

-	return key_lastpress == 'y';

-}

-

-

-//=============================================================================

-

-/*

-===============

-SCR_BringDownConsole

-

-Brings the console down and fades the palettes back to normal

-================

-*/

-void SCR_BringDownConsole (void)

-{

-	int		i;

-	

-	scr_centertime_off = 0;

-	

-	for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)

-		SCR_UpdateScreen ();

-

-	cl.cshifts[0].percent = 0;		// no area contents palette on next frame

-	VID_SetPalette (host_basepal);

-}

-

-

-/*

-==================

-SCR_UpdateScreen

-

-This is called every frame, and can also be called explicitly to flush

-text to the screen.

-

-WARNING: be very careful calling this from elsewhere, because the refresh

-needs almost the entire 256k of stack space!

-==================

-*/

-void SCR_UpdateScreen (void)

-{

-	static float	oldscr_viewsize;

-	static float	oldlcd_x;

-	vrect_t		vrect;

-	

-	if (scr_skipupdate || block_drawing)

-		return;

-

-	scr_copytop = 0;

-	scr_copyeverything = 0;

-

-	if (scr_disabled_for_loading)

-	{

-		if (realtime - scr_disabled_time > 60)

-		{

-			scr_disabled_for_loading = false;

-			Con_Printf ("load failed.\n");

-		}

-		else

-			return;

-	}

-

-	if (cls.state == ca_dedicated)

-		return;				// stdout only

-

-	if (!scr_initialized || !con_initialized)

-		return;				// not initialized yet

-

-	if (scr_viewsize.value != oldscr_viewsize)

-	{

-		oldscr_viewsize = scr_viewsize.value;

-		vid.recalc_refdef = 1;

-	}

-	

-//

-// check for vid changes

-//

-	if (oldfov != scr_fov.value)

-	{

-		oldfov = scr_fov.value;

-		vid.recalc_refdef = true;

-	}

-	

-	if (oldlcd_x != lcd_x.value)

-	{

-		oldlcd_x = lcd_x.value;

-		vid.recalc_refdef = true;

-	}

-	

-	if (oldscreensize != scr_viewsize.value)

-	{

-		oldscreensize = scr_viewsize.value;

-		vid.recalc_refdef = true;

-	}

-	

-	if (vid.recalc_refdef)

-	{

-	// something changed, so reorder the screen

-		SCR_CalcRefdef ();

-	}

-

-//

-// do 3D refresh drawing, and then update the screen

-//

-	D_EnableBackBufferAccess ();	// of all overlay stuff if drawing directly

-

-	if (scr_fullupdate++ < vid.numpages)

-	{	// clear the entire screen

-		scr_copyeverything = 1;

-		Draw_TileClear (0,0,vid.width,vid.height);

-		Sbar_Changed ();

-	}

-

-	pconupdate = NULL;

-

-

-	SCR_SetUpToDrawConsole ();

-	SCR_EraseCenterString ();

-

-	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in

-									//  for linear writes all the time

-

-	VID_LockBuffer ();

-

-	V_RenderView ();

-

-	VID_UnlockBuffer ();

-

-	D_EnableBackBufferAccess ();	// of all overlay stuff if drawing directly

-

-	if (scr_drawdialog)

-	{

-		Sbar_Draw ();

-		Draw_FadeScreen ();

-		SCR_DrawNotifyString ();

-		scr_copyeverything = true;

-	}

-	else if (scr_drawloading)

-	{

-		SCR_DrawLoading ();

-		Sbar_Draw ();

-	}

-	else if (cl.intermission == 1 && key_dest == key_game)

-	{

-		Sbar_IntermissionOverlay ();

-	}

-	else if (cl.intermission == 2 && key_dest == key_game)

-	{

-		Sbar_FinaleOverlay ();

-		SCR_CheckDrawCenterString ();

-	}

-	else if (cl.intermission == 3 && key_dest == key_game)

-	{

-		SCR_CheckDrawCenterString ();

-	}

-	else

-	{

-		SCR_DrawRam ();

-		SCR_DrawNet ();

-		SCR_DrawTurtle ();

-		SCR_DrawPause ();

-		SCR_CheckDrawCenterString ();

-		Sbar_Draw ();

-		SCR_DrawConsole ();

-		M_Draw ();

-	}

-

-	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in

-									//  for linear writes all the time

-	if (pconupdate)

-	{

-		D_UpdateRects (pconupdate);

-	}

-

-	V_UpdatePalette ();

-

-//

-// update one of three areas

-//

-

-	if (scr_copyeverything)

-	{

-		vrect.x = 0;

-		vrect.y = 0;

-		vrect.width = vid.width;

-		vrect.height = vid.height;

-		vrect.pnext = 0;

-	

-		VID_Update (&vrect);

-	}

-	else if (scr_copytop)

-	{

-		vrect.x = 0;

-		vrect.y = 0;

-		vrect.width = vid.width;

-		vrect.height = vid.height - sb_lines;

-		vrect.pnext = 0;

-	

-		VID_Update (&vrect);

-	}	

-	else

-	{

-		vrect.x = scr_vrect.x;

-		vrect.y = scr_vrect.y;

-		vrect.width = scr_vrect.width;

-		vrect.height = scr_vrect.height;

-		vrect.pnext = 0;

-	

-		VID_Update (&vrect);

-	}

-}

-

-

-/*

-==================

-SCR_UpdateWholeScreen

-==================

-*/

-void SCR_UpdateWholeScreen (void)

-{

-	scr_fullupdate = 0;

-	SCR_UpdateScreen ();

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// screen.c -- master for refresh, status bar, console, chat, notify, etc
+
+#include "quakedef.h"
+#include "r_local.h"
+
+// only the refresh window will be updated unless these variables are flagged 
+int			scr_copytop;
+int			scr_copyeverything;
+
+float		scr_con_current;
+float		scr_conlines;		// lines of console to display
+
+float		oldscreensize, oldfov;
+cvar_t		scr_viewsize = {"viewsize","100", true};
+cvar_t		scr_fov = {"fov","90"};	// 10 - 170
+cvar_t		scr_conspeed = {"scr_conspeed","300"};
+cvar_t		scr_centertime = {"scr_centertime","2"};
+cvar_t		scr_showram = {"showram","1"};
+cvar_t		scr_showturtle = {"showturtle","0"};
+cvar_t		scr_showpause = {"showpause","1"};
+cvar_t		scr_printspeed = {"scr_printspeed","8"};
+
+qboolean	scr_initialized;		// ready to draw
+
+qpic_t		*scr_ram;
+qpic_t		*scr_net;
+qpic_t		*scr_turtle;
+
+int			scr_fullupdate;
+
+int			clearconsole;
+int			clearnotify;
+
+viddef_t	vid;				// global video state
+
+vrect_t		*pconupdate;
+vrect_t		scr_vrect;
+
+qboolean	scr_disabled_for_loading;
+qboolean	scr_drawloading;
+float		scr_disabled_time;
+qboolean	scr_skipupdate;
+
+qboolean	block_drawing;
+
+void SCR_ScreenShot_f (void);
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+char		scr_centerstring[1024];
+float		scr_centertime_start;	// for slow victory printing
+float		scr_centertime_off;
+int			scr_center_lines;
+int			scr_erase_lines;
+int			scr_erase_center;
+
+/*
+==============
+SCR_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void SCR_CenterPrint (char *str)
+{
+	strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
+	scr_centertime_off = scr_centertime.value;
+	scr_centertime_start = cl.time;
+
+// count the number of lines for centering
+	scr_center_lines = 1;
+	while (*str)
+	{
+		if (*str == '\n')
+			scr_center_lines++;
+		str++;
+	}
+}
+
+void SCR_EraseCenterString (void)
+{
+	int		y;
+
+	if (scr_erase_center++ > vid.numpages)
+	{
+		scr_erase_lines = 0;
+		return;
+	}
+
+	if (scr_center_lines <= 4)
+		y = vid.height*0.35;
+	else
+		y = 48;
+
+	scr_copytop = 1;
+	Draw_TileClear (0, y,vid.width, 8*scr_erase_lines);
+}
+
+void SCR_DrawCenterString (void)
+{
+	char	*start;
+	int		l;
+	int		j;
+	int		x, y;
+	int		remaining;
+
+// the finale prints the characters one at a time
+	if (cl.intermission)
+		remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
+	else
+		remaining = 9999;
+
+	scr_erase_center = 0;
+	start = scr_centerstring;
+
+	if (scr_center_lines <= 4)
+		y = vid.height*0.35;
+	else
+		y = 48;
+
+	do	
+	{
+	// scan the width of the line
+		for (l=0 ; l<40 ; l++)
+			if (start[l] == '\n' || !start[l])
+				break;
+		x = (vid.width - l*8)/2;
+		for (j=0 ; j<l ; j++, x+=8)
+		{
+			Draw_Character (x, y, start[j]);	
+			if (!remaining--)
+				return;
+		}
+			
+		y += 8;
+
+		while (*start && *start != '\n')
+			start++;
+
+		if (!*start)
+			break;
+		start++;		// skip the \n
+	} while (1);
+}
+
+void SCR_CheckDrawCenterString (void)
+{
+	scr_copytop = 1;
+	if (scr_center_lines > scr_erase_lines)
+		scr_erase_lines = scr_center_lines;
+
+	scr_centertime_off -= host_frametime;
+	
+	if (scr_centertime_off <= 0 && !cl.intermission)
+		return;
+	if (key_dest != key_game)
+		return;
+
+	SCR_DrawCenterString ();
+}
+
+//=============================================================================
+
+/*
+====================
+CalcFov
+====================
+*/
+float CalcFov (float fov_x, float width, float height)
+{
+        float   a;
+        float   x;
+
+        if (fov_x < 1 || fov_x > 179)
+                Sys_Error ("Bad fov: %f", fov_x);
+
+        x = width/tan(fov_x/360*M_PI);
+
+        a = atan (height/x);
+
+        a = a*360/M_PI;
+
+        return a;
+}
+
+/*
+=================
+SCR_CalcRefdef
+
+Must be called whenever vid changes
+Internal use only
+=================
+*/
+static void SCR_CalcRefdef (void)
+{
+	vrect_t		vrect;
+	float		size;
+
+	scr_fullupdate = 0;		// force a background redraw
+	vid.recalc_refdef = 0;
+
+// force the status bar to redraw
+	Sbar_Changed ();
+
+//========================================
+	
+// bound viewsize
+	if (scr_viewsize.value < 30)
+		Cvar_Set ("viewsize","30");
+	if (scr_viewsize.value > 120)
+		Cvar_Set ("viewsize","120");
+
+// bound field of view
+	if (scr_fov.value < 10)
+		Cvar_Set ("fov","10");
+	if (scr_fov.value > 170)
+		Cvar_Set ("fov","170");
+
+	r_refdef.fov_x = scr_fov.value;
+	r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
+
+// intermission is always full screen	
+	if (cl.intermission)
+		size = 120;
+	else
+		size = scr_viewsize.value;
+
+	if (size >= 120)
+		sb_lines = 0;		// no status bar at all
+	else if (size >= 110)
+		sb_lines = 24;		// no inventory
+	else
+		sb_lines = 24+16+8;
+
+// these calculations mirror those in R_Init() for r_refdef, but take no
+// account of water warping
+	vrect.x = 0;
+	vrect.y = 0;
+	vrect.width = vid.width;
+	vrect.height = vid.height;
+
+	R_SetVrect (&vrect, &scr_vrect, sb_lines);
+
+// guard against going from one mode to another that's less than half the
+// vertical resolution
+	if (scr_con_current > vid.height)
+		scr_con_current = vid.height;
+
+// notify the refresh of the change
+	R_ViewChanged (&vrect, sb_lines, vid.aspect);
+}
+
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize.value+10);
+	vid.recalc_refdef = 1;
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+	Cvar_SetValue ("viewsize",scr_viewsize.value-10);
+	vid.recalc_refdef = 1;
+}
+
+//============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+	Cvar_RegisterVariable (&scr_fov);
+	Cvar_RegisterVariable (&scr_viewsize);
+	Cvar_RegisterVariable (&scr_conspeed);
+	Cvar_RegisterVariable (&scr_showram);
+	Cvar_RegisterVariable (&scr_showturtle);
+	Cvar_RegisterVariable (&scr_showpause);
+	Cvar_RegisterVariable (&scr_centertime);
+	Cvar_RegisterVariable (&scr_printspeed);
+
+//
+// register our commands
+//
+	Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
+	Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+	Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+
+	scr_ram = Draw_PicFromWad ("ram");
+	scr_net = Draw_PicFromWad ("net");
+	scr_turtle = Draw_PicFromWad ("turtle");
+
+	scr_initialized = true;
+}
+
+
+
+/*
+==============
+SCR_DrawRam
+==============
+*/
+void SCR_DrawRam (void)
+{
+	if (!scr_showram.value)
+		return;
+
+	if (!r_cache_thrash)
+		return;
+
+	Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
+}
+
+/*
+==============
+SCR_DrawTurtle
+==============
+*/
+void SCR_DrawTurtle (void)
+{
+	static int	count;
+	
+	if (!scr_showturtle.value)
+		return;
+
+	if (host_frametime < 0.1)
+	{
+		count = 0;
+		return;
+	}
+
+	count++;
+	if (count < 3)
+		return;
+
+	Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
+}
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+	if (realtime - cl.last_received_message < 0.3)
+		return;
+	if (cls.demoplayback)
+		return;
+
+	Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
+}
+
+/*
+==============
+DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+	qpic_t	*pic;
+
+	if (!scr_showpause.value)		// turn off for screenshots
+		return;
+
+	if (!cl.paused)
+		return;
+
+	pic = Draw_CachePic ("gfx/pause.lmp");
+	Draw_Pic ( (vid.width - pic->width)/2, 
+		(vid.height - 48 - pic->height)/2, pic);
+}
+
+
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+void SCR_DrawLoading (void)
+{
+	qpic_t	*pic;
+
+	if (!scr_drawloading)
+		return;
+		
+	pic = Draw_CachePic ("gfx/loading.lmp");
+	Draw_Pic ( (vid.width - pic->width)/2, 
+		(vid.height - 48 - pic->height)/2, pic);
+}
+
+
+
+//=============================================================================
+
+
+/*
+==================
+SCR_SetUpToDrawConsole
+==================
+*/
+void SCR_SetUpToDrawConsole (void)
+{
+	Con_CheckResize ();
+	
+	if (scr_drawloading)
+		return;		// never a console with loading plaque
+		
+// decide on the height of the console
+	con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
+
+	if (con_forcedup)
+	{
+		scr_conlines = vid.height;		// full screen
+		scr_con_current = scr_conlines;
+	}
+	else if (key_dest == key_console)
+		scr_conlines = vid.height/2;	// half screen
+	else
+		scr_conlines = 0;				// none visible
+	
+	if (scr_conlines < scr_con_current)
+	{
+		scr_con_current -= scr_conspeed.value*host_frametime;
+		if (scr_conlines > scr_con_current)
+			scr_con_current = scr_conlines;
+
+	}
+	else if (scr_conlines > scr_con_current)
+	{
+		scr_con_current += scr_conspeed.value*host_frametime;
+		if (scr_conlines < scr_con_current)
+			scr_con_current = scr_conlines;
+	}
+
+	if (clearconsole++ < vid.numpages)
+	{
+		scr_copytop = 1;
+		Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current);
+		Sbar_Changed ();
+	}
+	else if (clearnotify++ < vid.numpages)
+	{
+		scr_copytop = 1;
+		Draw_TileClear (0,0,vid.width, con_notifylines);
+	}
+	else
+		con_notifylines = 0;
+}
+	
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+	if (scr_con_current)
+	{
+		scr_copyeverything = 1;
+		Con_DrawConsole (scr_con_current, true);
+		clearconsole = 0;
+	}
+	else
+	{
+		if (key_dest == key_game || key_dest == key_message)
+			Con_DrawNotify ();	// only draw notify in game
+	}
+}
+
+
+/* 
+============================================================================== 
+ 
+						SCREEN SHOTS 
+ 
+============================================================================== 
+*/ 
+ 
+
+typedef struct
+{
+    char	manufacturer;
+    char	version;
+    char	encoding;
+    char	bits_per_pixel;
+    unsigned short	xmin,ymin,xmax,ymax;
+    unsigned short	hres,vres;
+    unsigned char	palette[48];
+    char	reserved;
+    char	color_planes;
+    unsigned short	bytes_per_line;
+    unsigned short	palette_type;
+    char	filler[58];
+    unsigned char	data;			// unbounded
+} pcx_t;
+
+/* 
+============== 
+WritePCXfile 
+============== 
+*/ 
+void WritePCXfile (char *filename, byte *data, int width, int height,
+	int rowbytes, byte *palette) 
+{
+	int		i, j, length;
+	pcx_t	*pcx;
+	byte		*pack;
+	  
+	pcx = Hunk_TempAlloc (width*height*2+1000);
+	if (pcx == NULL)
+	{
+		Con_Printf("SCR_ScreenShot_f: not enough memory\n");
+		return;
+	} 
+ 
+	pcx->manufacturer = 0x0a;	// PCX id
+	pcx->version = 5;			// 256 color
+ 	pcx->encoding = 1;		// uncompressed
+	pcx->bits_per_pixel = 8;		// 256 color
+	pcx->xmin = 0;
+	pcx->ymin = 0;
+	pcx->xmax = LittleShort((short)(width-1));
+	pcx->ymax = LittleShort((short)(height-1));
+	pcx->hres = LittleShort((short)width);
+	pcx->vres = LittleShort((short)height);
+	Q_memset (pcx->palette,0,sizeof(pcx->palette));
+	pcx->color_planes = 1;		// chunky image
+	pcx->bytes_per_line = LittleShort((short)width);
+	pcx->palette_type = LittleShort(2);		// not a grey scale
+	Q_memset (pcx->filler,0,sizeof(pcx->filler));
+
+// pack the image
+	pack = &pcx->data;
+	
+	for (i=0 ; i<height ; i++)
+	{
+		for (j=0 ; j<width ; j++)
+		{
+			if ( (*data & 0xc0) != 0xc0)
+				*pack++ = *data++;
+			else
+			{
+				*pack++ = 0xc1;
+				*pack++ = *data++;
+			}
+		}
+
+		data += rowbytes - width;
+	}
+			
+// write the palette
+	*pack++ = 0x0c;	// palette ID byte
+	for (i=0 ; i<768 ; i++)
+		*pack++ = *palette++;
+		
+// write output file 
+	length = pack - (byte *)pcx;
+	COM_WriteFile (filename, pcx, length);
+} 
+ 
+
+
+/* 
+================== 
+SCR_ScreenShot_f
+================== 
+*/  
+void SCR_ScreenShot_f (void) 
+{ 
+	int     i; 
+	char		pcxname[80]; 
+	char		checkname[MAX_OSPATH];
+
+// 
+// find a file name to save it to 
+// 
+	strcpy(pcxname,"quake00.pcx");
+		
+	for (i=0 ; i<=99 ; i++) 
+	{ 
+		pcxname[5] = i/10 + '0'; 
+		pcxname[6] = i%10 + '0'; 
+		sprintf (checkname, "%s/%s", com_gamedir, pcxname);
+		if (Sys_FileTime(checkname) == -1)
+			break;	// file doesn't exist
+	} 
+	if (i==100) 
+	{
+		Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n"); 
+		return;
+ 	}
+
+// 
+// save the pcx file 
+// 
+	D_EnableBackBufferAccess ();	// enable direct drawing of console to back
+									//  buffer
+
+	WritePCXfile (pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes,
+				  host_basepal);
+
+	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in
+									//  for linear writes all the time
+
+	Con_Printf ("Wrote %s\n", pcxname);
+} 
+
+
+//=============================================================================
+
+
+/*
+===============
+SCR_BeginLoadingPlaque
+
+================
+*/
+void SCR_BeginLoadingPlaque (void)
+{
+	S_StopAllSounds (true);
+
+	if (cls.state != ca_connected)
+		return;
+	if (cls.signon != SIGNONS)
+		return;
+	
+// redraw with no console and the loading plaque
+	Con_ClearNotify ();
+	scr_centertime_off = 0;
+	scr_con_current = 0;
+
+	scr_drawloading = true;
+	scr_fullupdate = 0;
+	Sbar_Changed ();
+	SCR_UpdateScreen ();
+	scr_drawloading = false;
+
+	scr_disabled_for_loading = true;
+	scr_disabled_time = realtime;
+	scr_fullupdate = 0;
+}
+
+/*
+===============
+SCR_EndLoadingPlaque
+
+================
+*/
+void SCR_EndLoadingPlaque (void)
+{
+	scr_disabled_for_loading = false;
+	scr_fullupdate = 0;
+	Con_ClearNotify ();
+}
+
+//=============================================================================
+
+char	*scr_notifystring;
+qboolean	scr_drawdialog;
+
+void SCR_DrawNotifyString (void)
+{
+	char	*start;
+	int		l;
+	int		j;
+	int		x, y;
+
+	start = scr_notifystring;
+
+	y = vid.height*0.35;
+
+	do	
+	{
+	// scan the width of the line
+		for (l=0 ; l<40 ; l++)
+			if (start[l] == '\n' || !start[l])
+				break;
+		x = (vid.width - l*8)/2;
+		for (j=0 ; j<l ; j++, x+=8)
+			Draw_Character (x, y, start[j]);	
+			
+		y += 8;
+
+		while (*start && *start != '\n')
+			start++;
+
+		if (!*start)
+			break;
+		start++;		// skip the \n
+	} while (1);
+}
+
+/*
+==================
+SCR_ModalMessage
+
+Displays a text string in the center of the screen and waits for a Y or N
+keypress.  
+==================
+*/
+int SCR_ModalMessage (const char *text)
+{
+	if (cls.state == ca_dedicated)
+		return true;
+
+	scr_notifystring = text;
+ 
+// draw a fresh screen
+	scr_fullupdate = 0;
+	scr_drawdialog = true;
+	SCR_UpdateScreen ();
+	scr_drawdialog = false;
+	
+	S_ClearBuffer ();		// so dma doesn't loop current sound
+
+	do
+	{
+		key_count = -1;		// wait for a key down and up
+		Sys_SendKeyEvents ();
+	} while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
+
+	scr_fullupdate = 0;
+	SCR_UpdateScreen ();
+
+	return key_lastpress == 'y';
+}
+
+
+//=============================================================================
+
+/*
+===============
+SCR_BringDownConsole
+
+Brings the console down and fades the palettes back to normal
+================
+*/
+void SCR_BringDownConsole (void)
+{
+	int		i;
+	
+	scr_centertime_off = 0;
+	
+	for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
+		SCR_UpdateScreen ();
+
+	cl.cshifts[0].percent = 0;		// no area contents palette on next frame
+	VID_SetPalette (host_basepal);
+}
+
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+
+WARNING: be very careful calling this from elsewhere, because the refresh
+needs almost the entire 256k of stack space!
+==================
+*/
+void SCR_UpdateScreen (void)
+{
+	static float	oldscr_viewsize;
+	static float	oldlcd_x;
+	vrect_t		vrect;
+	
+	if (scr_skipupdate || block_drawing)
+		return;
+
+	scr_copytop = 0;
+	scr_copyeverything = 0;
+
+	if (scr_disabled_for_loading)
+	{
+		if (realtime - scr_disabled_time > 60)
+		{
+			scr_disabled_for_loading = false;
+			Con_Printf ("load failed.\n");
+		}
+		else
+			return;
+	}
+
+	if (cls.state == ca_dedicated)
+		return;				// stdout only
+
+	if (!scr_initialized || !con_initialized)
+		return;				// not initialized yet
+
+	if (scr_viewsize.value != oldscr_viewsize)
+	{
+		oldscr_viewsize = scr_viewsize.value;
+		vid.recalc_refdef = 1;
+	}
+	
+//
+// check for vid changes
+//
+	if (oldfov != scr_fov.value)
+	{
+		oldfov = scr_fov.value;
+		vid.recalc_refdef = true;
+	}
+	
+	if (oldlcd_x != lcd_x.value)
+	{
+		oldlcd_x = lcd_x.value;
+		vid.recalc_refdef = true;
+	}
+	
+	if (oldscreensize != scr_viewsize.value)
+	{
+		oldscreensize = scr_viewsize.value;
+		vid.recalc_refdef = true;
+	}
+	
+	if (vid.recalc_refdef)
+	{
+	// something changed, so reorder the screen
+		SCR_CalcRefdef ();
+	}
+
+//
+// do 3D refresh drawing, and then update the screen
+//
+	D_EnableBackBufferAccess ();	// of all overlay stuff if drawing directly
+
+	if (scr_fullupdate++ < vid.numpages)
+	{	// clear the entire screen
+		scr_copyeverything = 1;
+		Draw_TileClear (0,0,vid.width,vid.height);
+		Sbar_Changed ();
+	}
+
+	pconupdate = NULL;
+
+
+	SCR_SetUpToDrawConsole ();
+	SCR_EraseCenterString ();
+
+	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in
+									//  for linear writes all the time
+
+	VID_LockBuffer ();
+
+	V_RenderView ();
+
+	VID_UnlockBuffer ();
+
+	D_EnableBackBufferAccess ();	// of all overlay stuff if drawing directly
+
+	if (scr_drawdialog)
+	{
+		Sbar_Draw ();
+		Draw_FadeScreen ();
+		SCR_DrawNotifyString ();
+		scr_copyeverything = true;
+	}
+	else if (scr_drawloading)
+	{
+		SCR_DrawLoading ();
+		Sbar_Draw ();
+	}
+	else if (cl.intermission == 1 && key_dest == key_game)
+	{
+		Sbar_IntermissionOverlay ();
+	}
+	else if (cl.intermission == 2 && key_dest == key_game)
+	{
+		Sbar_FinaleOverlay ();
+		SCR_CheckDrawCenterString ();
+	}
+	else if (cl.intermission == 3 && key_dest == key_game)
+	{
+		SCR_CheckDrawCenterString ();
+	}
+	else
+	{
+		SCR_DrawRam ();
+		SCR_DrawNet ();
+		SCR_DrawTurtle ();
+		SCR_DrawPause ();
+		SCR_CheckDrawCenterString ();
+		Sbar_Draw ();
+		SCR_DrawConsole ();
+		M_Draw ();
+	}
+
+	D_DisableBackBufferAccess ();	// for adapters that can't stay mapped in
+									//  for linear writes all the time
+	if (pconupdate)
+	{
+		D_UpdateRects (pconupdate);
+	}
+
+	V_UpdatePalette ();
+
+//
+// update one of three areas
+//
+
+	if (scr_copyeverything)
+	{
+		vrect.x = 0;
+		vrect.y = 0;
+		vrect.width = vid.width;
+		vrect.height = vid.height;
+		vrect.pnext = 0;
+	
+		VID_Update (&vrect);
+	}
+	else if (scr_copytop)
+	{
+		vrect.x = 0;
+		vrect.y = 0;
+		vrect.width = vid.width;
+		vrect.height = vid.height - sb_lines;
+		vrect.pnext = 0;
+	
+		VID_Update (&vrect);
+	}	
+	else
+	{
+		vrect.x = scr_vrect.x;
+		vrect.y = scr_vrect.y;
+		vrect.width = scr_vrect.width;
+		vrect.height = scr_vrect.height;
+		vrect.pnext = 0;
+	
+		VID_Update (&vrect);
+	}
+}
+
+
+/*
+==================
+SCR_UpdateWholeScreen
+==================
+*/
+void SCR_UpdateWholeScreen (void)
+{
+	scr_fullupdate = 0;
+	SCR_UpdateScreen ();
+}
diff --git a/quake/src/WinQuake/screen.h b/quake/src/WinQuake/screen.h
index 154f3e0..0ee7a34 100644
--- a/quake/src/WinQuake/screen.h
+++ b/quake/src/WinQuake/screen.h
@@ -1,57 +1,57 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// screen.h

-

-void SCR_Init (void);

-

-void SCR_UpdateScreen (void);

-

-

-void SCR_SizeUp (void);

-void SCR_SizeDown (void);

-void SCR_BringDownConsole (void);

-void SCR_CenterPrint (char *str);

-

-void SCR_BeginLoadingPlaque (void);

-void SCR_EndLoadingPlaque (void);

-

-int SCR_ModalMessage (char *text);

-

-extern	float		scr_con_current;

-extern	float		scr_conlines;		// lines of console to display

-

-extern	int			scr_fullupdate;	// set to 0 to force full redraw

-extern	int			sb_lines;

-

-extern	int			clearnotify;	// set to 0 whenever notify text is drawn

-extern	qboolean	scr_disabled_for_loading;

-extern	qboolean	scr_skipupdate;

-

-extern	cvar_t		scr_viewsize;

-

-extern cvar_t scr_viewsize;

-

-// only the refresh window will be updated unless these variables are flagged 

-extern	int			scr_copytop;

-extern	int			scr_copyeverything;

-

-extern qboolean		block_drawing;

-

-void SCR_UpdateWholeScreen (void);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// screen.h
+
+void SCR_Init (void);
+
+void SCR_UpdateScreen (void);
+
+
+void SCR_SizeUp (void);
+void SCR_SizeDown (void);
+void SCR_BringDownConsole (void);
+void SCR_CenterPrint (char *str);
+
+void SCR_BeginLoadingPlaque (void);
+void SCR_EndLoadingPlaque (void);
+
+int SCR_ModalMessage (const char *text);
+
+extern	float		scr_con_current;
+extern	float		scr_conlines;		// lines of console to display
+
+extern	int			scr_fullupdate;	// set to 0 to force full redraw
+extern	int			sb_lines;
+
+extern	int			clearnotify;	// set to 0 whenever notify text is drawn
+extern	qboolean	scr_disabled_for_loading;
+extern	qboolean	scr_skipupdate;
+
+extern	cvar_t		scr_viewsize;
+
+extern cvar_t scr_viewsize;
+
+// only the refresh window will be updated unless these variables are flagged 
+extern	int			scr_copytop;
+extern	int			scr_copyeverything;
+
+extern qboolean		block_drawing;
+
+void SCR_UpdateWholeScreen (void);
diff --git a/quake/src/WinQuake/server.h b/quake/src/WinQuake/server.h
index e63c99e..4e2abb9 100644
--- a/quake/src/WinQuake/server.h
+++ b/quake/src/WinQuake/server.h
@@ -1,257 +1,257 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// server.h

-

-typedef struct

-{

-	int			maxclients;

-	int			maxclientslimit;

-	struct client_s	*clients;		// [maxclients]

-	int			serverflags;		// episode completion information

-	qboolean	changelevel_issued;	// cleared when at SV_SpawnServer

-} server_static_t;

-

-//=============================================================================

-

-typedef enum {ss_loading, ss_active} server_state_t;

-

-typedef struct

-{

-	qboolean	active;				// false if only a net client

-

-	qboolean	paused;

-	qboolean	loadgame;			// handle connections specially

-

-	double		time;

-	

-	int			lastcheck;			// used by PF_checkclient

-	double		lastchecktime;

-	

-	char		name[64];			// map name

-#ifdef QUAKE2

-	char		startspot[64];

-#endif

-	char		modelname[64];		// maps/<name>.bsp, for model_precache[0]

-	struct model_s 	*worldmodel;

-	char		*model_precache[MAX_MODELS];	// NULL terminated

-	struct model_s	*models[MAX_MODELS];

-	char		*sound_precache[MAX_SOUNDS];	// NULL terminated

-	char		*lightstyles[MAX_LIGHTSTYLES];

-	int			num_edicts;

-	int			max_edicts;

-	edict_t		*edicts;			// can NOT be array indexed, because

-									// edict_t is variable sized, but can

-									// be used to reference the world ent

-	server_state_t	state;			// some actions are only valid during load

-

-	sizebuf_t	datagram;

-	byte		datagram_buf[MAX_DATAGRAM];

-

-	sizebuf_t	reliable_datagram;	// copied to all clients at end of frame

-	byte		reliable_datagram_buf[MAX_DATAGRAM];

-

-	sizebuf_t	signon;

-	byte		signon_buf[8192];

-} server_t;

-

-

-#define	NUM_PING_TIMES		16

-#define	NUM_SPAWN_PARMS		16

-

-typedef struct client_s

-{

-	qboolean		active;				// false = client is free

-	qboolean		spawned;			// false = don't send datagrams

-	qboolean		dropasap;			// has been told to go to another level

-	qboolean		privileged;			// can execute any host command

-	qboolean		sendsignon;			// only valid before spawned

-

-	double			last_message;		// reliable messages must be sent

-										// periodically

-

-	struct qsocket_s *netconnection;	// communications handle

-

-	usercmd_t		cmd;				// movement

-	vec3_t			wishdir;			// intended motion calced from cmd

-

-	sizebuf_t		message;			// can be added to at any time,

-										// copied and clear once per frame

-	byte			msgbuf[MAX_MSGLEN];

-	edict_t			*edict;				// EDICT_NUM(clientnum+1)

-	char			name[32];			// for printing to other people

-	int				colors;

-		

-	float			ping_times[NUM_PING_TIMES];

-	int				num_pings;			// ping_times[num_pings%NUM_PING_TIMES]

-

-// spawn parms are carried from level to level

-	float			spawn_parms[NUM_SPAWN_PARMS];

-

-// client known data for deltas	

-	int				old_frags;

-} client_t;

-

-

-//=============================================================================

-

-// edict->movetype values

-#define	MOVETYPE_NONE			0		// never moves

-#define	MOVETYPE_ANGLENOCLIP	1

-#define	MOVETYPE_ANGLECLIP		2

-#define	MOVETYPE_WALK			3		// gravity

-#define	MOVETYPE_STEP			4		// gravity, special edge handling

-#define	MOVETYPE_FLY			5

-#define	MOVETYPE_TOSS			6		// gravity

-#define	MOVETYPE_PUSH			7		// no clip to world, push and crush

-#define	MOVETYPE_NOCLIP			8

-#define	MOVETYPE_FLYMISSILE		9		// extra size to monsters

-#define	MOVETYPE_BOUNCE			10

-#ifdef QUAKE2

-#define MOVETYPE_BOUNCEMISSILE	11		// bounce w/o gravity

-#define MOVETYPE_FOLLOW			12		// track movement of aiment

-#endif

-

-// edict->solid values

-#define	SOLID_NOT				0		// no interaction with other objects

-#define	SOLID_TRIGGER			1		// touch on edge, but not blocking

-#define	SOLID_BBOX				2		// touch on edge, block

-#define	SOLID_SLIDEBOX			3		// touch on edge, but not an onground

-#define	SOLID_BSP				4		// bsp clip, touch on edge, block

-

-// edict->deadflag values

-#define	DEAD_NO					0

-#define	DEAD_DYING				1

-#define	DEAD_DEAD				2

-

-#define	DAMAGE_NO				0

-#define	DAMAGE_YES				1

-#define	DAMAGE_AIM				2

-

-// edict->flags

-#define	FL_FLY					1

-#define	FL_SWIM					2

-//#define	FL_GLIMPSE				4

-#define	FL_CONVEYOR				4

-#define	FL_CLIENT				8

-#define	FL_INWATER				16

-#define	FL_MONSTER				32

-#define	FL_GODMODE				64

-#define	FL_NOTARGET				128

-#define	FL_ITEM					256

-#define	FL_ONGROUND				512

-#define	FL_PARTIALGROUND		1024	// not all corners are valid

-#define	FL_WATERJUMP			2048	// player jumping out of water

-#define	FL_JUMPRELEASED			4096	// for jump debouncing

-#ifdef QUAKE2

-#define FL_FLASHLIGHT			8192

-#define FL_ARCHIVE_OVERRIDE		1048576

-#endif

-

-// entity effects

-

-#define	EF_BRIGHTFIELD			1

-#define	EF_MUZZLEFLASH 			2

-#define	EF_BRIGHTLIGHT 			4

-#define	EF_DIMLIGHT 			8

-#ifdef QUAKE2

-#define EF_DARKLIGHT			16

-#define EF_DARKFIELD			32

-#define EF_LIGHT				64

-#define EF_NODRAW				128

-#endif

-

-#define	SPAWNFLAG_NOT_EASY			256

-#define	SPAWNFLAG_NOT_MEDIUM		512

-#define	SPAWNFLAG_NOT_HARD			1024

-#define	SPAWNFLAG_NOT_DEATHMATCH	2048

-

-#ifdef QUAKE2

-// server flags

-#define	SFL_EPISODE_1		1

-#define	SFL_EPISODE_2		2

-#define	SFL_EPISODE_3		4

-#define	SFL_EPISODE_4		8

-#define	SFL_NEW_UNIT		16

-#define	SFL_NEW_EPISODE		32

-#define	SFL_CROSS_TRIGGERS	65280

-#endif

-

-//============================================================================

-

-extern	cvar_t	teamplay;

-extern	cvar_t	skill;

-extern	cvar_t	deathmatch;

-extern	cvar_t	coop;

-extern	cvar_t	fraglimit;

-extern	cvar_t	timelimit;

-

-extern	server_static_t	svs;				// persistant server info

-extern	server_t		sv;					// local server

-

-extern	client_t	*host_client;

-

-extern	jmp_buf 	host_abortserver;

-

-extern	double		host_time;

-

-extern	edict_t		*sv_player;

-

-//===========================================================

-

-void SV_Init (void);

-

-void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);

-void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,

-    float attenuation);

-

-void SV_DropClient (qboolean crash);

-

-void SV_SendClientMessages (void);

-void SV_ClearDatagram (void);

-

-int SV_ModelIndex (char *name);

-

-void SV_SetIdealPitch (void);

-

-void SV_AddUpdates (void);

-

-void SV_ClientThink (void);

-void SV_AddClientToServer (struct qsocket_s	*ret);

-

-void SV_ClientPrintf (char *fmt, ...);

-void SV_BroadcastPrintf (char *fmt, ...);

-

-void SV_Physics (void);

-

-qboolean SV_CheckBottom (edict_t *ent);

-qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink);

-

-void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg);

-

-void SV_MoveToGoal (void);

-

-void SV_CheckForNewClients (void);

-void SV_RunClients (void);

-void SV_SaveSpawnparms ();

-#ifdef QUAKE2

-void SV_SpawnServer (char *server, char *startspot);

-#else

-void SV_SpawnServer (char *server);

-#endif

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// server.h
+
+typedef struct
+{
+	int			maxclients;
+	int			maxclientslimit;
+	struct client_s	*clients;		// [maxclients]
+	int			serverflags;		// episode completion information
+	qboolean	changelevel_issued;	// cleared when at SV_SpawnServer
+} server_static_t;
+
+//=============================================================================
+
+typedef enum {ss_loading, ss_active, server_state_t_max = 1 << 30} server_state_t;
+
+typedef struct
+{
+	qboolean	active;				// false if only a net client
+
+	qboolean	paused;
+	qboolean	loadgame;			// handle connections specially
+
+	double		time;
+	
+	int			lastcheck;			// used by PF_checkclient
+	double		lastchecktime;
+	
+	char		name[64];			// map name
+#ifdef QUAKE2
+	char		startspot[64];
+#endif
+	char		modelname[64];		// maps/<name>.bsp, for model_precache[0]
+	struct model_s 	*worldmodel;
+	char		*model_precache[MAX_MODELS];	// NULL terminated
+	struct model_s	*models[MAX_MODELS];
+	char		*sound_precache[MAX_SOUNDS];	// NULL terminated
+	char		*lightstyles[MAX_LIGHTSTYLES];
+	int			num_edicts;
+	int			max_edicts;
+	edict_t		*edicts;			// can NOT be array indexed, because
+									// edict_t is variable sized, but can
+									// be used to reference the world ent
+	server_state_t	state;			// some actions are only valid during load
+
+	sizebuf_t	datagram;
+	byte		datagram_buf[MAX_DATAGRAM];
+
+	sizebuf_t	reliable_datagram;	// copied to all clients at end of frame
+	byte		reliable_datagram_buf[MAX_DATAGRAM];
+
+	sizebuf_t	signon;
+	byte		signon_buf[8192];
+} server_t;
+
+
+#define	NUM_PING_TIMES		16
+#define	NUM_SPAWN_PARMS		16
+
+typedef struct client_s
+{
+	qboolean		active;				// false = client is free
+	qboolean		spawned;			// false = don't send datagrams
+	qboolean		dropasap;			// has been told to go to another level
+	qboolean		privileged;			// can execute any host command
+	qboolean		sendsignon;			// only valid before spawned
+
+	double			last_message;		// reliable messages must be sent
+										// periodically
+
+	struct qsocket_s *netconnection;	// communications handle
+
+	usercmd_t		cmd;				// movement
+	vec3_t			wishdir;			// intended motion calced from cmd
+
+	sizebuf_t		message;			// can be added to at any time,
+										// copied and clear once per frame
+	byte			msgbuf[MAX_MSGLEN];
+	edict_t			*edict;				// EDICT_NUM(clientnum+1)
+	char			name[32];			// for printing to other people
+	int				colors;
+		
+	float			ping_times[NUM_PING_TIMES];
+	int				num_pings;			// ping_times[num_pings%NUM_PING_TIMES]
+
+// spawn parms are carried from level to level
+	float			spawn_parms[NUM_SPAWN_PARMS];
+
+// client known data for deltas	
+	int				old_frags;
+} client_t;
+
+
+//=============================================================================
+
+// edict->movetype values
+#define	MOVETYPE_NONE			0		// never moves
+#define	MOVETYPE_ANGLENOCLIP	1
+#define	MOVETYPE_ANGLECLIP		2
+#define	MOVETYPE_WALK			3		// gravity
+#define	MOVETYPE_STEP			4		// gravity, special edge handling
+#define	MOVETYPE_FLY			5
+#define	MOVETYPE_TOSS			6		// gravity
+#define	MOVETYPE_PUSH			7		// no clip to world, push and crush
+#define	MOVETYPE_NOCLIP			8
+#define	MOVETYPE_FLYMISSILE		9		// extra size to monsters
+#define	MOVETYPE_BOUNCE			10
+#ifdef QUAKE2
+#define MOVETYPE_BOUNCEMISSILE	11		// bounce w/o gravity
+#define MOVETYPE_FOLLOW			12		// track movement of aiment
+#endif
+
+// edict->solid values
+#define	SOLID_NOT				0		// no interaction with other objects
+#define	SOLID_TRIGGER			1		// touch on edge, but not blocking
+#define	SOLID_BBOX				2		// touch on edge, block
+#define	SOLID_SLIDEBOX			3		// touch on edge, but not an onground
+#define	SOLID_BSP				4		// bsp clip, touch on edge, block
+
+// edict->deadflag values
+#define	DEAD_NO					0
+#define	DEAD_DYING				1
+#define	DEAD_DEAD				2
+
+#define	DAMAGE_NO				0
+#define	DAMAGE_YES				1
+#define	DAMAGE_AIM				2
+
+// edict->flags
+#define	FL_FLY					1
+#define	FL_SWIM					2
+//#define	FL_GLIMPSE				4
+#define	FL_CONVEYOR				4
+#define	FL_CLIENT				8
+#define	FL_INWATER				16
+#define	FL_MONSTER				32
+#define	FL_GODMODE				64
+#define	FL_NOTARGET				128
+#define	FL_ITEM					256
+#define	FL_ONGROUND				512
+#define	FL_PARTIALGROUND		1024	// not all corners are valid
+#define	FL_WATERJUMP			2048	// player jumping out of water
+#define	FL_JUMPRELEASED			4096	// for jump debouncing
+#ifdef QUAKE2
+#define FL_FLASHLIGHT			8192
+#define FL_ARCHIVE_OVERRIDE		1048576
+#endif
+
+// entity effects
+
+#define	EF_BRIGHTFIELD			1
+#define	EF_MUZZLEFLASH 			2
+#define	EF_BRIGHTLIGHT 			4
+#define	EF_DIMLIGHT 			8
+#ifdef QUAKE2
+#define EF_DARKLIGHT			16
+#define EF_DARKFIELD			32
+#define EF_LIGHT				64
+#define EF_NODRAW				128
+#endif
+
+#define	SPAWNFLAG_NOT_EASY			256
+#define	SPAWNFLAG_NOT_MEDIUM		512
+#define	SPAWNFLAG_NOT_HARD			1024
+#define	SPAWNFLAG_NOT_DEATHMATCH	2048
+
+#ifdef QUAKE2
+// server flags
+#define	SFL_EPISODE_1		1
+#define	SFL_EPISODE_2		2
+#define	SFL_EPISODE_3		4
+#define	SFL_EPISODE_4		8
+#define	SFL_NEW_UNIT		16
+#define	SFL_NEW_EPISODE		32
+#define	SFL_CROSS_TRIGGERS	65280
+#endif
+
+//============================================================================
+
+extern	cvar_t	teamplay;
+extern	cvar_t	skill;
+extern	cvar_t	deathmatch;
+extern	cvar_t	coop;
+extern	cvar_t	fraglimit;
+extern	cvar_t	timelimit;
+
+extern	server_static_t	svs;				// persistant server info
+extern	server_t		sv;					// local server
+
+extern	client_t	*host_client;
+
+extern	jmp_buf 	host_abortserver;
+
+extern	double		host_time;
+
+extern	edict_t		*sv_player;
+
+//===========================================================
+
+void SV_Init (void);
+
+void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);
+void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
+    float attenuation);
+
+void SV_DropClient (qboolean crash);
+
+void SV_SendClientMessages (void);
+void SV_ClearDatagram (void);
+
+int SV_ModelIndex (const char *name);
+
+void SV_SetIdealPitch (void);
+
+void SV_AddUpdates (void);
+
+void SV_ClientThink (void);
+void SV_AddClientToServer (struct qsocket_s	*ret);
+
+void SV_ClientPrintf (const char *fmt, ...);
+void SV_BroadcastPrintf (const char *fmt, ...);
+
+void SV_Physics (void);
+
+qboolean SV_CheckBottom (edict_t *ent);
+qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink);
+
+void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg);
+
+void SV_MoveToGoal (void);
+
+void SV_CheckForNewClients (void);
+void SV_RunClients (void);
+void SV_SaveSpawnparms ();
+#ifdef QUAKE2
+void SV_SpawnServer (char *server, char *startspot);
+#else
+void SV_SpawnServer (char *server);
+#endif
diff --git a/quake/src/WinQuake/snd_android.cpp b/quake/src/WinQuake/snd_android.cpp
new file mode 100644
index 0000000..f8973b4
--- /dev/null
+++ b/quake/src/WinQuake/snd_android.cpp
@@ -0,0 +1,349 @@
+/*
+ *  snd_android.c
+ *  Android-specific sound interface
+ *
+ */
+
+#include "quakedef.h"
+
+#include <pthread.h>
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <media/AudioTrack.h>
+
+using namespace android;
+
+static AudioTrack gAudioTrack;
+
+// Written by the callback function running in an audio thread.
+// index in bytes of where we last read.
+
+static volatile size_t gDMAByteIndex;
+
+
+// Written by main thread
+static size_t gAvailableBytes;
+static bool gSoundMixingStarted;
+
+// The condition is "new data is now available"
+
+static pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  condition_cond  = PTHREAD_COND_INITIALIZER;
+
+/*
+==================
+SNDDMA_Init
+
+Try to find a sound device to mix for.
+Returns false if nothing is found.
+==================
+*/
+
+
+const size_t SAMPLE_RATE = 11025;
+
+
+const size_t BYTES_PER_SAMPLE = 2;
+const size_t CHANNEL_COUNT = 2;
+const size_t BITS_PER_SAMPLE = 8 * BYTES_PER_SAMPLE;
+
+const size_t TOTAL_BUFFER_SIZE = 16 * 1024;
+
+static size_t min(size_t a, size_t b) {
+  return a < b ? a : b;
+}
+
+static size_t mod(size_t value, size_t mod) {
+  return value % mod;
+}
+
+static size_t next(size_t value, size_t mod) {
+  value = value + 1;
+  if ( value >= mod ) {
+    value = 0;
+  }
+  return value;
+}
+
+static size_t prev(size_t value, size_t mod) {
+  if ( value <= 0 ) {
+    value = mod;
+  }
+  return value - 1;
+}
+
+
+static bool enableSound() {
+
+    if (COM_CheckParm("-nosound"))
+        return false;
+
+  return true;
+}
+
+// Choose one:
+
+// #define GENERATE_SINE_WAVE
+#define NORMAL_SOUND
+
+#ifdef GENERATE_SINE_WAVE
+
+static const float p = 2 * M_PI * 440.0f / SAMPLE_RATE;
+static float left = 0.0f;
+static float right = 0.0f;
+
+static float sinef(float x)
+{
+    const float A =   1.0f / (2.0f*M_PI);
+    const float B = -16.0f;
+    const float C =   8.0f;
+
+    // scale angle for easy argument reduction
+    x *= A;
+
+    if (fabsf(x) >= 0.5f) {
+        // Argument reduction
+        x = x - ceilf(x + 0.5f) + 1.0f;
+    }
+
+    const float y = B*x*fabsf(x) + C*x;
+    return 0.2215f * (y*fabsf(y) - y) + y;
+}
+
+static
+void AndroidQuakeSoundCallback(int event, void* user, void *info) {
+
+    if (event != AudioTrack::EVENT_MORE_DATA) return;
+
+    const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
+    size_t bytesToCopy = buffer->size;
+    size_t framesToCopy = buffer->size / (BYTES_PER_SAMPLE * CHANNEL_COUNT);
+    short* pData = buffer->i16;
+
+    for(size_t frame = 0; frame < framesToCopy; frame++) {
+        short leftSample = (short) (32767.0f * sinef(left));
+        left += p;
+        if (left > 2*M_PI) {
+            left -= 2*M_PI;
+        }
+        pData[frame * CHANNEL_COUNT] = leftSample;
+
+        short rightSample = (short) (32767.0f * sinef(right));
+        right += 2 * p;
+        if (right > 2*M_PI) {
+            right -= 2*M_PI;
+        }
+        pData[1 + frame * CHANNEL_COUNT] = rightSample;
+    }
+
+    gDMAByteIndex = mod(gDMAByteIndex + bytesToCopy, TOTAL_BUFFER_SIZE);
+    asm volatile ("":::"memory");
+}
+
+#endif
+
+#ifdef NORMAL_SOUND
+
+static bool gWaitingForMixerToRestart;
+
+// Assumes the mutex is acquired.
+// Waits until audio is available or a time period has elapsed.
+static bool shouldMixSilence() {
+  if (!gSoundMixingStarted) {
+    return true;
+  }
+    while (gAvailableBytes == 0) {
+      if (gWaitingForMixerToRestart) {
+        return true;
+      }
+        timeval tp;
+        if (gettimeofday(&tp, NULL)) {
+          return true;
+        }
+     const long WAIT_NS = 40 * 1000 * 1000;
+     const long NS_PER_SECOND = 1000 * 1000 * 1000;
+     timespec ts;
+     ts.tv_sec  = tp.tv_sec;
+     ts.tv_nsec = tp.tv_usec * 1000 + WAIT_NS;
+     if (ts.tv_nsec >= NS_PER_SECOND) {
+       ts.tv_nsec -= NS_PER_SECOND;
+       ts.tv_sec += 1;
+     }
+     if (ETIMEDOUT == pthread_cond_timedwait( &condition_cond,  &condition_mutex, &ts)) {
+       gWaitingForMixerToRestart = true;
+       return true;
+     }
+    }
+    gWaitingForMixerToRestart = false;
+    return false;
+}
+
+static
+void AndroidQuakeSoundCallback(int event, void* user, void *info) {
+
+    if (event != AudioTrack::EVENT_MORE_DATA) return;
+
+    const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
+    size_t dmaByteIndex = gDMAByteIndex;
+    size_t size = buffer->size;
+    unsigned char* pDestBuffer = (unsigned char*) buffer->raw;
+
+    if (size == 0) return;
+
+    if ( ! shm ) {
+        memset(pDestBuffer, 0, size);
+        return;
+    }
+
+    const unsigned char* pSrcBuffer = shm->buffer;
+
+    while(size > 0) {
+        pthread_mutex_lock( &condition_mutex );
+
+        if (shouldMixSilence()) {
+          memset(pDestBuffer, 0, size);
+          pthread_mutex_unlock( &condition_mutex );
+          return;
+        }
+
+        size_t chunkSize = min(gAvailableBytes, min(TOTAL_BUFFER_SIZE-dmaByteIndex, size));
+        gAvailableBytes -= chunkSize;
+
+        pthread_mutex_unlock( &condition_mutex );
+
+    memcpy(pDestBuffer, pSrcBuffer + dmaByteIndex, chunkSize);
+    size -= chunkSize;
+    pDestBuffer += chunkSize;
+    dmaByteIndex += chunkSize;
+    if (dmaByteIndex >= TOTAL_BUFFER_SIZE) {
+      dmaByteIndex = 0;
+    }
+  }
+
+  gDMAByteIndex = dmaByteIndex;
+  asm volatile ("":::"memory");
+}
+
+#endif
+
+qboolean SNDDMA_Init(void)
+{
+  if ( ! enableSound() ) {
+    return false;
+  }
+
+  gDMAByteIndex = 0;
+
+  // Initialize the AudioTrack.
+
+  status_t result = gAudioTrack.set(
+    AudioSystem::DEFAULT, // stream type
+    SAMPLE_RATE,   // sample rate
+    BITS_PER_SAMPLE == 16 ? AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT,      // format (8 or 16)
+    CHANNEL_COUNT,       // channel count
+    0,       // default buffer size
+    0, // flags
+    AndroidQuakeSoundCallback, // callback
+    0,  // user
+    0); // default notification size
+
+  LOGI("AudioTrack status  = %d (%s)\n", result, result == NO_ERROR ? "success" : "error");
+
+  if ( result == NO_ERROR ) {
+    LOGI("AudioTrack latency = %u ms\n", gAudioTrack.latency());
+    LOGI("AudioTrack format = %u bits\n", gAudioTrack.format() == AudioSystem::PCM_16_BIT ? 16 : 8);
+    LOGI("AudioTrack sample rate = %u Hz\n", gAudioTrack.sampleRate());
+    LOGI("AudioTrack frame count = %d\n", int(gAudioTrack.frameCount()));
+    LOGI("AudioTrack channel count = %d\n", gAudioTrack.channelCount());
+
+    // Initialize Quake's idea of a DMA buffer.
+
+    shm = &sn;
+    memset((void*)&sn, 0, sizeof(sn));
+
+    shm->splitbuffer = false;	// Not used.
+    shm->samplebits = gAudioTrack.format() == AudioSystem::PCM_16_BIT ? 16 : 8;
+    shm->speed = gAudioTrack.sampleRate();
+    shm->channels = gAudioTrack.channelCount();
+    shm->samples = TOTAL_BUFFER_SIZE / BYTES_PER_SAMPLE;
+    shm->samplepos = 0; // Not used.
+    shm->buffer = (unsigned char*) Hunk_AllocName(TOTAL_BUFFER_SIZE, (char*) "shmbuf");
+    shm->submission_chunk = 1; // Not used.
+
+    shm->soundalive = true;
+
+    if ( (shm->samples & 0x1ff) != 0 ) {
+      LOGE("SNDDDMA_Init: samples must be power of two.");
+      return false;
+    }
+
+    if ( shm->buffer == 0 ) {
+      LOGE("SNDDDMA_Init: Could not allocate sound buffer.");
+      return false;
+    }
+
+    gAudioTrack.setVolume(1.0f, 1.0f);
+    gAudioTrack.start();
+  }
+
+  return result == NO_ERROR;
+}
+
+/*
+==============
+SNDDMA_GetDMAPos
+
+return the current sample position (in mono samples read)
+inside the recirculating dma buffer, so the mixing code will know
+how many sample are required to fill it up.
+===============
+*/
+int SNDDMA_GetDMAPos(void)
+{
+  int dmaPos = gDMAByteIndex / BYTES_PER_SAMPLE;
+  asm volatile ("":::"memory");
+  return dmaPos;
+}
+
+/*
+===============
+SNDDMA_ReportWrite
+
+Report valid data being written into the DMA buffer by the sound mixing code.
+This is an Android specific API.
+================
+*/
+void SNDDMA_ReportWrite(size_t lengthBytes) {
+    pthread_mutex_lock( &condition_mutex );
+    gSoundMixingStarted = true;
+    if (gAvailableBytes == 0) {
+        pthread_cond_signal( &condition_cond );
+    }
+    gAvailableBytes += lengthBytes;
+    pthread_mutex_unlock( &condition_mutex );
+}
+
+/*
+==============
+SNDDMA_Submit
+
+Send sound to device if buffer isn't really the dma buffer
+===============
+*/
+void SNDDMA_Submit(void)
+{
+}
+
+/*
+==============
+SNDDMA_Shutdown
+
+Reset the sound device for exiting
+===============
+*/
+void SNDDMA_Shutdown(void)
+{
+  gAudioTrack.stop();
+}
diff --git a/quake/src/WinQuake/snd_dma.c b/quake/src/WinQuake/snd_dma.cpp
old mode 100644
new mode 100755
similarity index 92%
rename from quake/src/WinQuake/snd_dma.c
rename to quake/src/WinQuake/snd_dma.cpp
index accb617..4be4876
--- a/quake/src/WinQuake/snd_dma.c
+++ b/quake/src/WinQuake/snd_dma.cpp
@@ -1,1017 +1,1024 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// snd_dma.c -- main control for any streaming sound output device

-

-#include "quakedef.h"

-

-#ifdef _WIN32

-#include "winquake.h"

-#endif

-

-void S_Play(void);

-void S_PlayVol(void);

-void S_SoundList(void);

-void S_Update_();

-void S_StopAllSounds(qboolean clear);

-void S_StopAllSoundsC(void);

-

-// =======================================================================

-// Internal sound data & structures

-// =======================================================================

-

-channel_t   channels[MAX_CHANNELS];

-int			total_channels;

-

-int				snd_blocked = 0;

-static qboolean	snd_ambient = 1;

-qboolean		snd_initialized = false;

-

-// pointer should go away

-volatile dma_t  *shm = 0;

-volatile dma_t sn;

-

-vec3_t		listener_origin;

-vec3_t		listener_forward;

-vec3_t		listener_right;

-vec3_t		listener_up;

-vec_t		sound_nominal_clip_dist=1000.0;

-

-int			soundtime;		// sample PAIRS

-int   		paintedtime; 	// sample PAIRS

-

-

-#define	MAX_SFX		512

-sfx_t		*known_sfx;		// hunk allocated [MAX_SFX]

-int			num_sfx;

-

-sfx_t		*ambient_sfx[NUM_AMBIENTS];

-

-int 		desired_speed = 11025;

-int 		desired_bits = 16;

-

-int sound_started=0;

-

-cvar_t bgmvolume = {"bgmvolume", "1", true};

-cvar_t volume = {"volume", "0.7", true};

-

-cvar_t nosound = {"nosound", "0"};

-cvar_t precache = {"precache", "1"};

-cvar_t loadas8bit = {"loadas8bit", "0"};

-cvar_t bgmbuffer = {"bgmbuffer", "4096"};

-cvar_t ambient_level = {"ambient_level", "0.3"};

-cvar_t ambient_fade = {"ambient_fade", "100"};

-cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"};

-cvar_t snd_show = {"snd_show", "0"};

-cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true};

-

-

-// ====================================================================

-// User-setable variables

-// ====================================================================

-

-

-//

-// Fake dma is a synchronous faking of the DMA progress used for

-// isolating performance in the renderer.  The fakedma_updates is

-// number of times S_Update() is called per second.

-//

-

-qboolean fakedma = false;

-int fakedma_updates = 15;

-

-

-void S_AmbientOff (void)

-{

-	snd_ambient = false;

-}

-

-

-void S_AmbientOn (void)

-{

-	snd_ambient = true;

-}

-

-

-void S_SoundInfo_f(void)

-{

-	if (!sound_started || !shm)

-	{

-		Con_Printf ("sound system not started\n");

-		return;

-	}

-	

-    Con_Printf("%5d stereo\n", shm->channels - 1);

-    Con_Printf("%5d samples\n", shm->samples);

-    Con_Printf("%5d samplepos\n", shm->samplepos);

-    Con_Printf("%5d samplebits\n", shm->samplebits);

-    Con_Printf("%5d submission_chunk\n", shm->submission_chunk);

-    Con_Printf("%5d speed\n", shm->speed);

-    Con_Printf("0x%x dma buffer\n", shm->buffer);

-	Con_Printf("%5d total_channels\n", total_channels);

-}

-

-

-/*

-================

-S_Startup

-================

-*/

-

-void S_Startup (void)

-{

-	int		rc;

-

-	if (!snd_initialized)

-		return;

-

-	if (!fakedma)

-	{

-		rc = SNDDMA_Init();

-

-		if (!rc)

-		{

-#ifndef	_WIN32

-			Con_Printf("S_Startup: SNDDMA_Init failed.\n");

-#endif

-			sound_started = 0;

-			return;

-		}

-	}

-

-	sound_started = 1;

-}

-

-

-/*

-================

-S_Init

-================

-*/

-void S_Init (void)

-{

-

-	Con_Printf("\nSound Initialization\n");

-

-	if (COM_CheckParm("-nosound"))

-		return;

-

-	if (COM_CheckParm("-simsound"))

-		fakedma = true;

-

-	Cmd_AddCommand("play", S_Play);

-	Cmd_AddCommand("playvol", S_PlayVol);

-	Cmd_AddCommand("stopsound", S_StopAllSoundsC);

-	Cmd_AddCommand("soundlist", S_SoundList);

-	Cmd_AddCommand("soundinfo", S_SoundInfo_f);

-

-	Cvar_RegisterVariable(&nosound);

-	Cvar_RegisterVariable(&volume);

-	Cvar_RegisterVariable(&precache);

-	Cvar_RegisterVariable(&loadas8bit);

-	Cvar_RegisterVariable(&bgmvolume);

-	Cvar_RegisterVariable(&bgmbuffer);

-	Cvar_RegisterVariable(&ambient_level);

-	Cvar_RegisterVariable(&ambient_fade);

-	Cvar_RegisterVariable(&snd_noextraupdate);

-	Cvar_RegisterVariable(&snd_show);

-	Cvar_RegisterVariable(&_snd_mixahead);

-

-	if (host_parms.memsize < 0x800000)

-	{

-		Cvar_Set ("loadas8bit", "1");

-		Con_Printf ("loading all sounds as 8bit\n");

-	}

-

-

-

-	snd_initialized = true;

-

-	S_Startup ();

-

-	SND_InitScaletable ();

-

-	known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");

-	num_sfx = 0;

-

-// create a piece of DMA memory

-

-	if (fakedma)

-	{

-		shm = (void *) Hunk_AllocName(sizeof(*shm), "shm");

-		shm->splitbuffer = 0;

-		shm->samplebits = 16;

-		shm->speed = 22050;

-		shm->channels = 2;

-		shm->samples = 32768;

-		shm->samplepos = 0;

-		shm->soundalive = true;

-		shm->gamealive = true;

-		shm->submission_chunk = 1;

-		shm->buffer = Hunk_AllocName(1<<16, "shmbuf");

-	}

-

-	Con_Printf ("Sound sampling rate: %i\n", shm->speed);

-

-	// provides a tick sound until washed clean

-

-//	if (shm->buffer)

-//		shm->buffer[4] = shm->buffer[5] = 0x7f;	// force a pop for debugging

-

-	ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");

-	ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");

-

-	S_StopAllSounds (true);

-}

-

-

-// =======================================================================

-// Shutdown sound engine

-// =======================================================================

-

-void S_Shutdown(void)

-{

-

-	if (!sound_started)

-		return;

-

-	if (shm)

-		shm->gamealive = 0;

-

-	shm = 0;

-	sound_started = 0;

-

-	if (!fakedma)

-	{

-		SNDDMA_Shutdown();

-	}

-}

-

-

-// =======================================================================

-// Load a sound

-// =======================================================================

-

-/*

-==================

-S_FindName

-

-==================

-*/

-sfx_t *S_FindName (char *name)

-{

-	int		i;

-	sfx_t	*sfx;

-

-	if (!name)

-		Sys_Error ("S_FindName: NULL\n");

-

-	if (Q_strlen(name) >= MAX_QPATH)

-		Sys_Error ("Sound name too long: %s", name);

-

-// see if already loaded

-	for (i=0 ; i < num_sfx ; i++)

-		if (!Q_strcmp(known_sfx[i].name, name))

-		{

-			return &known_sfx[i];

-		}

-

-	if (num_sfx == MAX_SFX)

-		Sys_Error ("S_FindName: out of sfx_t");

-	

-	sfx = &known_sfx[i];

-	strcpy (sfx->name, name);

-

-	num_sfx++;

-	

-	return sfx;

-}

-

-

-/*

-==================

-S_TouchSound

-

-==================

-*/

-void S_TouchSound (char *name)

-{

-	sfx_t	*sfx;

-	

-	if (!sound_started)

-		return;

-

-	sfx = S_FindName (name);

-	Cache_Check (&sfx->cache);

-}

-

-/*

-==================

-S_PrecacheSound

-

-==================

-*/

-sfx_t *S_PrecacheSound (char *name)

-{

-	sfx_t	*sfx;

-

-	if (!sound_started || nosound.value)

-		return NULL;

-

-	sfx = S_FindName (name);

-	

-// cache it in

-	if (precache.value)

-		S_LoadSound (sfx);

-	

-	return sfx;

-}

-

-

-//=============================================================================

-

-/*

-=================

-SND_PickChannel

-=================

-*/

-channel_t *SND_PickChannel(int entnum, int entchannel)

-{

-    int ch_idx;

-    int first_to_die;

-    int life_left;

-

-// Check for replacement sound, or find the best one to replace

-    first_to_die = -1;

-    life_left = 0x7fffffff;

-    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)

-    {

-		if (entchannel != 0		// channel 0 never overrides

-		&& channels[ch_idx].entnum == entnum

-		&& (channels[ch_idx].entchannel == entchannel || entchannel == -1) )

-		{	// allways override sound from same entity

-			first_to_die = ch_idx;

-			break;

-		}

-

-		// don't let monster sounds override player sounds

-		if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)

-			continue;

-

-		if (channels[ch_idx].end - paintedtime < life_left)

-		{

-			life_left = channels[ch_idx].end - paintedtime;

-			first_to_die = ch_idx;

-		}

-   }

-

-	if (first_to_die == -1)

-		return NULL;

-

-	if (channels[first_to_die].sfx)

-		channels[first_to_die].sfx = NULL;

-

-    return &channels[first_to_die];    

-}       

-

-/*

-=================

-SND_Spatialize

-=================

-*/

-void SND_Spatialize(channel_t *ch)

-{

-    vec_t dot;

-    vec_t ldist, rdist, dist;

-    vec_t lscale, rscale, scale;

-    vec3_t source_vec;

-	sfx_t *snd;

-

-// anything coming from the view entity will allways be full volume

-	if (ch->entnum == cl.viewentity)

-	{

-		ch->leftvol = ch->master_vol;

-		ch->rightvol = ch->master_vol;

-		return;

-	}

-

-// calculate stereo seperation and distance attenuation

-

-	snd = ch->sfx;

-	VectorSubtract(ch->origin, listener_origin, source_vec);

-	

-	dist = VectorNormalize(source_vec) * ch->dist_mult;

-	

-	dot = DotProduct(listener_right, source_vec);

-

-	if (shm->channels == 1)

-	{

-		rscale = 1.0;

-		lscale = 1.0;

-	}

-	else

-	{

-		rscale = 1.0 + dot;

-		lscale = 1.0 - dot;

-	}

-

-// add in distance effect

-	scale = (1.0 - dist) * rscale;

-	ch->rightvol = (int) (ch->master_vol * scale);

-	if (ch->rightvol < 0)

-		ch->rightvol = 0;

-

-	scale = (1.0 - dist) * lscale;

-	ch->leftvol = (int) (ch->master_vol * scale);

-	if (ch->leftvol < 0)

-		ch->leftvol = 0;

-}           

-

-

-// =======================================================================

-// Start a sound effect

-// =======================================================================

-

-void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)

-{

-	channel_t *target_chan, *check;

-	sfxcache_t	*sc;

-	int		vol;

-	int		ch_idx;

-	int		skip;

-

-	if (!sound_started)

-		return;

-

-	if (!sfx)

-		return;

-

-	if (nosound.value)

-		return;

-

-	vol = fvol*255;

-

-// pick a channel to play on

-	target_chan = SND_PickChannel(entnum, entchannel);

-	if (!target_chan)

-		return;

-		

-// spatialize

-	memset (target_chan, 0, sizeof(*target_chan));

-	VectorCopy(origin, target_chan->origin);

-	target_chan->dist_mult = attenuation / sound_nominal_clip_dist;

-	target_chan->master_vol = vol;

-	target_chan->entnum = entnum;

-	target_chan->entchannel = entchannel;

-	SND_Spatialize(target_chan);

-

-	if (!target_chan->leftvol && !target_chan->rightvol)

-		return;		// not audible at all

-

-// new channel

-	sc = S_LoadSound (sfx);

-	if (!sc)

-	{

-		target_chan->sfx = NULL;

-		return;		// couldn't load the sound's data

-	}

-

-	target_chan->sfx = sfx;

-	target_chan->pos = 0.0;

-    target_chan->end = paintedtime + sc->length;	

-

-// if an identical sound has also been started this frame, offset the pos

-// a bit to keep it from just making the first one louder

-	check = &channels[NUM_AMBIENTS];

-    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)

-    {

-		if (check == target_chan)

-			continue;

-		if (check->sfx == sfx && !check->pos)

-		{

-			skip = rand () % (int)(0.1*shm->speed);

-			if (skip >= target_chan->end)

-				skip = target_chan->end - 1;

-			target_chan->pos += skip;

-			target_chan->end -= skip;

-			break;

-		}

-		

-	}

-}

-

-void S_StopSound(int entnum, int entchannel)

-{

-	int i;

-

-	for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)

-	{

-		if (channels[i].entnum == entnum

-			&& channels[i].entchannel == entchannel)

-		{

-			channels[i].end = 0;

-			channels[i].sfx = NULL;

-			return;

-		}

-	}

-}

-

-void S_StopAllSounds(qboolean clear)

-{

-	int		i;

-

-	if (!sound_started)

-		return;

-

-	total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;	// no statics

-

-	for (i=0 ; i<MAX_CHANNELS ; i++)

-		if (channels[i].sfx)

-			channels[i].sfx = NULL;

-

-	Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));

-

-	if (clear)

-		S_ClearBuffer ();

-}

-

-void S_StopAllSoundsC (void)

-{

-	S_StopAllSounds (true);

-}

-

-void S_ClearBuffer (void)

-{

-	int		clear;

-		

-#ifdef _WIN32

-	if (!sound_started || !shm || (!shm->buffer && !pDSBuf))

-#else

-	if (!sound_started || !shm || !shm->buffer)

-#endif

-		return;

-

-	if (shm->samplebits == 8)

-		clear = 0x80;

-	else

-		clear = 0;

-

-#ifdef _WIN32

-	if (pDSBuf)

-	{

-		DWORD	dwSize;

-		DWORD	*pData;

-		int		reps;

-		HRESULT	hresult;

-

-		reps = 0;

-

-		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK)

-		{

-			if (hresult != DSERR_BUFFERLOST)

-			{

-				Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");

-				S_Shutdown ();

-				return;

-			}

-

-			if (++reps > 10000)

-			{

-				Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n");

-				S_Shutdown ();

-				return;

-			}

-		}

-

-		Q_memset(pData, clear, shm->samples * shm->samplebits/8);

-

-		pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);

-	

-	}

-	else

-#endif

-	{

-		Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8);

-	}

-}

-

-

-/*

-=================

-S_StaticSound

-=================

-*/

-void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)

-{

-	channel_t	*ss;

-	sfxcache_t		*sc;

-

-	if (!sfx)

-		return;

-

-	if (total_channels == MAX_CHANNELS)

-	{

-		Con_Printf ("total_channels == MAX_CHANNELS\n");

-		return;

-	}

-

-	ss = &channels[total_channels];

-	total_channels++;

-

-	sc = S_LoadSound (sfx);

-	if (!sc)

-		return;

-

-	if (sc->loopstart == -1)

-	{

-		Con_Printf ("Sound %s not looped\n", sfx->name);

-		return;

-	}

-	

-	ss->sfx = sfx;

-	VectorCopy (origin, ss->origin);

-	ss->master_vol = vol;

-	ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;

-    ss->end = paintedtime + sc->length;	

-	

-	SND_Spatialize (ss);

-}

-

-

-//=============================================================================

-

-/*

-===================

-S_UpdateAmbientSounds

-===================

-*/

-void S_UpdateAmbientSounds (void)

-{

-	mleaf_t		*l;

-	float		vol;

-	int			ambient_channel;

-	channel_t	*chan;

-

-	if (!snd_ambient)

-		return;

-

-// calc ambient sound levels

-	if (!cl.worldmodel)

-		return;

-

-	l = Mod_PointInLeaf (listener_origin, cl.worldmodel);

-	if (!l || !ambient_level.value)

-	{

-		for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)

-			channels[ambient_channel].sfx = NULL;

-		return;

-	}

-

-	for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)

-	{

-		chan = &channels[ambient_channel];	

-		chan->sfx = ambient_sfx[ambient_channel];

-	

-		vol = ambient_level.value * l->ambient_sound_level[ambient_channel];

-		if (vol < 8)

-			vol = 0;

-

-	// don't adjust volume too fast

-		if (chan->master_vol < vol)

-		{

-			chan->master_vol += host_frametime * ambient_fade.value;

-			if (chan->master_vol > vol)

-				chan->master_vol = vol;

-		}

-		else if (chan->master_vol > vol)

-		{

-			chan->master_vol -= host_frametime * ambient_fade.value;

-			if (chan->master_vol < vol)

-				chan->master_vol = vol;

-		}

-		

-		chan->leftvol = chan->rightvol = chan->master_vol;

-	}

-}

-

-

-/*

-============

-S_Update

-

-Called once each time through the main loop

-============

-*/

-void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)

-{

-	int			i, j;

-	int			total;

-	channel_t	*ch;

-	channel_t	*combine;

-

-	if (!sound_started || (snd_blocked > 0))

-		return;

-

-	VectorCopy(origin, listener_origin);

-	VectorCopy(forward, listener_forward);

-	VectorCopy(right, listener_right);

-	VectorCopy(up, listener_up);

-	

-// update general area ambient sound sources

-	S_UpdateAmbientSounds ();

-

-	combine = NULL;

-

-// update spatialization for static and dynamic sounds	

-	ch = channels+NUM_AMBIENTS;

-	for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)

-	{

-		if (!ch->sfx)

-			continue;

-		SND_Spatialize(ch);         // respatialize channel

-		if (!ch->leftvol && !ch->rightvol)

-			continue;

-

-	// try to combine static sounds with a previous channel of the same

-	// sound effect so we don't mix five torches every frame

-	

-		if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)

-		{

-		// see if it can just use the last one

-			if (combine && combine->sfx == ch->sfx)

-			{

-				combine->leftvol += ch->leftvol;

-				combine->rightvol += ch->rightvol;

-				ch->leftvol = ch->rightvol = 0;

-				continue;

-			}

-		// search for one

-			combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;

-			for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)

-				if (combine->sfx == ch->sfx)

-					break;

-					

-			if (j == total_channels)

-			{

-				combine = NULL;

-			}

-			else

-			{

-				if (combine != ch)

-				{

-					combine->leftvol += ch->leftvol;

-					combine->rightvol += ch->rightvol;

-					ch->leftvol = ch->rightvol = 0;

-				}

-				continue;

-			}

-		}

-		

-		

-	}

-

-//

-// debugging output

-//

-	if (snd_show.value)

-	{

-		total = 0;

-		ch = channels;

-		for (i=0 ; i<total_channels; i++, ch++)

-			if (ch->sfx && (ch->leftvol || ch->rightvol) )

-			{

-				//Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);

-				total++;

-			}

-		

-		Con_Printf ("----(%i)----\n", total);

-	}

-

-// mix some sound

-	S_Update_();

-}

-

-void GetSoundtime(void)

-{

-	int		samplepos;

-	static	int		buffers;

-	static	int		oldsamplepos;

-	int		fullsamples;

-	

-	fullsamples = shm->samples / shm->channels;

-

-// it is possible to miscount buffers if it has wrapped twice between

-// calls to S_Update.  Oh well.

-#ifdef __sun__

-	soundtime = SNDDMA_GetSamples();

-#else

-	samplepos = SNDDMA_GetDMAPos();

-

-

-	if (samplepos < oldsamplepos)

-	{

-		buffers++;					// buffer wrapped

-		

-		if (paintedtime > 0x40000000)

-		{	// time to chop things off to avoid 32 bit limits

-			buffers = 0;

-			paintedtime = fullsamples;

-			S_StopAllSounds (true);

-		}

-	}

-	oldsamplepos = samplepos;

-

-	soundtime = buffers*fullsamples + samplepos/shm->channels;

-#endif

-}

-

-void S_ExtraUpdate (void)

-{

-

-#ifdef _WIN32

-	IN_Accumulate ();

-#endif

-

-	if (snd_noextraupdate.value)

-		return;		// don't pollute timings

-	S_Update_();

-}

-

-void S_Update_(void)

-{

-	unsigned        endtime;

-	int				samps;

-	

-	if (!sound_started || (snd_blocked > 0))

-		return;

-

-// Updates DMA time

-	GetSoundtime();

-

-// check to make sure that we haven't overshot

-	if (paintedtime < soundtime)

-	{

-		//Con_Printf ("S_Update_ : overflow\n");

-		paintedtime = soundtime;

-	}

-

-// mix ahead of current position

-	endtime = soundtime + _snd_mixahead.value * shm->speed;

-	samps = shm->samples >> (shm->channels-1);

-	if (endtime - soundtime > samps)

-		endtime = soundtime + samps;

-

-#ifdef _WIN32

-// if the buffer was lost or stopped, restore it and/or restart it

-	{

-		DWORD	dwStatus;

-

-		if (pDSBuf)

-		{

-			if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)

-				Con_Printf ("Couldn't get sound buffer status\n");

-			

-			if (dwStatus & DSBSTATUS_BUFFERLOST)

-				pDSBuf->lpVtbl->Restore (pDSBuf);

-			

-			if (!(dwStatus & DSBSTATUS_PLAYING))

-				pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);

-		}

-	}

-#endif

-

-	S_PaintChannels (endtime);

-

-	SNDDMA_Submit ();

-}

-

-/*

-===============================================================================

-

-console functions

-

-===============================================================================

-*/

-

-void S_Play(void)

-{

-	static int hash=345;

-	int 	i;

-	char name[256];

-	sfx_t	*sfx;

-	

-	i = 1;

-	while (i<Cmd_Argc())

-	{

-		if (!Q_strrchr(Cmd_Argv(i), '.'))

-		{

-			Q_strcpy(name, Cmd_Argv(i));

-			Q_strcat(name, ".wav");

-		}

-		else

-			Q_strcpy(name, Cmd_Argv(i));

-		sfx = S_PrecacheSound(name);

-		S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);

-		i++;

-	}

-}

-

-void S_PlayVol(void)

-{

-	static int hash=543;

-	int i;

-	float vol;

-	char name[256];

-	sfx_t	*sfx;

-	

-	i = 1;

-	while (i<Cmd_Argc())

-	{

-		if (!Q_strrchr(Cmd_Argv(i), '.'))

-		{

-			Q_strcpy(name, Cmd_Argv(i));

-			Q_strcat(name, ".wav");

-		}

-		else

-			Q_strcpy(name, Cmd_Argv(i));

-		sfx = S_PrecacheSound(name);

-		vol = Q_atof(Cmd_Argv(i+1));

-		S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);

-		i+=2;

-	}

-}

-

-void S_SoundList(void)

-{

-	int		i;

-	sfx_t	*sfx;

-	sfxcache_t	*sc;

-	int		size, total;

-

-	total = 0;

-	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)

-	{

-		sc = Cache_Check (&sfx->cache);

-		if (!sc)

-			continue;

-		size = sc->length*sc->width*(sc->stereo+1);

-		total += size;

-		if (sc->loopstart >= 0)

-			Con_Printf ("L");

-		else

-			Con_Printf (" ");

-		Con_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);

-	}

-	Con_Printf ("Total resident: %i\n", total);

-}

-

-

-void S_LocalSound (char *sound)

-{

-	sfx_t	*sfx;

-

-	if (nosound.value)

-		return;

-	if (!sound_started)

-		return;

-		

-	sfx = S_PrecacheSound (sound);

-	if (!sfx)

-	{

-		Con_Printf ("S_LocalSound: can't cache %s\n", sound);

-		return;

-	}

-	S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);

-}

-

-

-void S_ClearPrecache (void)

-{

-}

-

-

-void S_BeginPrecaching (void)

-{

-}

-

-

-void S_EndPrecaching (void)

-{

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// snd_dma.c -- main control for any streaming sound output device
+
+#include "quakedef.h"
+
+#ifdef _WIN32
+#include "winquake.h"
+#endif
+
+void S_Play(void);
+void S_PlayVol(void);
+void S_SoundList(void);
+void S_Update_();
+void S_StopAllSounds(qboolean clear);
+void S_StopAllSoundsC(void);
+
+// =======================================================================
+// Internal sound data & structures
+// =======================================================================
+
+channel_t   channels[MAX_CHANNELS];
+int			total_channels;
+
+int				snd_blocked = 0;
+static qboolean	snd_ambient = 1;
+qboolean		snd_initialized = false;
+
+// pointer should go away
+volatile dma_t  *shm = 0;
+volatile dma_t sn;
+
+vec3_t		listener_origin;
+vec3_t		listener_forward;
+vec3_t		listener_right;
+vec3_t		listener_up;
+vec_t		sound_nominal_clip_dist=1000.0;
+
+int			soundtime;		// sample PAIRS
+int   		paintedtime; 	// sample PAIRS
+
+
+#define	MAX_SFX		512
+sfx_t		*known_sfx;		// hunk allocated [MAX_SFX]
+int			num_sfx;
+
+sfx_t		*ambient_sfx[NUM_AMBIENTS];
+
+int 		desired_speed = 11025;
+int 		desired_bits = 16;
+
+int sound_started=0;
+
+cvar_t bgmvolume = CVAR3("bgmvolume", "1", true);
+cvar_t volume = CVAR3("volume", "0.7", true);
+
+cvar_t nosound = CVAR2("nosound", "0");
+cvar_t precache = CVAR2("precache", "1");
+cvar_t loadas8bit = CVAR2("loadas8bit", "0");
+cvar_t bgmbuffer = CVAR2("bgmbuffer", "4096");
+cvar_t ambient_level = CVAR2("ambient_level", "0.3");
+cvar_t ambient_fade = CVAR2("ambient_fade", "100");
+cvar_t snd_noextraupdate = CVAR2("snd_noextraupdate", "0");
+cvar_t snd_show = CVAR2("snd_show", "0");
+cvar_t _snd_mixahead = CVAR3("_snd_mixahead", "0.1", true);
+
+
+// ====================================================================
+// User-setable variables
+// ====================================================================
+
+
+//
+// Fake dma is a synchronous faking of the DMA progress used for
+// isolating performance in the renderer.  The fakedma_updates is
+// number of times S_Update() is called per second.
+//
+
+qboolean fakedma = false;
+int fakedma_updates = 15;
+
+
+void S_AmbientOff (void)
+{
+	snd_ambient = false;
+}
+
+
+void S_AmbientOn (void)
+{
+	snd_ambient = true;
+}
+
+
+void S_SoundInfo_f(void)
+{
+	if (!sound_started || !shm)
+	{
+		Con_Printf ("sound system not started\n");
+		return;
+	}
+	
+    Con_Printf("%5d stereo\n", shm->channels - 1);
+    Con_Printf("%5d samples\n", shm->samples);
+    Con_Printf("%5d samplepos\n", shm->samplepos);
+    Con_Printf("%5d samplebits\n", shm->samplebits);
+    Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
+    Con_Printf("%5d speed\n", shm->speed);
+    Con_Printf("0x%x dma buffer\n", shm->buffer);
+	Con_Printf("%5d total_channels\n", total_channels);
+}
+
+
+/*
+================
+S_Startup
+================
+*/
+
+void S_Startup (void)
+{
+	int		rc;
+
+	if (!snd_initialized)
+		return;
+
+	if (!fakedma)
+	{
+		rc = SNDDMA_Init();
+
+		if (!rc)
+		{
+#ifndef	_WIN32
+			Con_Printf("S_Startup: SNDDMA_Init failed.\n");
+#endif
+			sound_started = 0;
+			return;
+		}
+	}
+
+	sound_started = 1;
+}
+
+
+/*
+================
+S_Init
+================
+*/
+void S_Init (void)
+{
+
+	Con_Printf("\nSound Initialization\n");
+
+	if (COM_CheckParm("-nosound"))
+		return;
+
+	if (COM_CheckParm("-simsound"))
+		fakedma = true;
+
+	Cmd_AddCommand("play", S_Play);
+	Cmd_AddCommand("playvol", S_PlayVol);
+	Cmd_AddCommand("stopsound", S_StopAllSoundsC);
+	Cmd_AddCommand("soundlist", S_SoundList);
+	Cmd_AddCommand("soundinfo", S_SoundInfo_f);
+
+	Cvar_RegisterVariable(&nosound);
+	Cvar_RegisterVariable(&volume);
+	Cvar_RegisterVariable(&precache);
+	Cvar_RegisterVariable(&loadas8bit);
+	Cvar_RegisterVariable(&bgmvolume);
+	Cvar_RegisterVariable(&bgmbuffer);
+	Cvar_RegisterVariable(&ambient_level);
+	Cvar_RegisterVariable(&ambient_fade);
+	Cvar_RegisterVariable(&snd_noextraupdate);
+	Cvar_RegisterVariable(&snd_show);
+	Cvar_RegisterVariable(&_snd_mixahead);
+
+	if (host_parms.memsize < 0x800000)
+	{
+		Cvar_Set ("loadas8bit", "1");
+		Con_Printf ("loading all sounds as 8bit\n");
+	}
+
+
+
+	snd_initialized = true;
+
+	S_Startup ();
+
+	SND_InitScaletable ();
+
+	known_sfx = (sfx_t*) Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");
+	num_sfx = 0;
+
+// create a piece of DMA memory
+
+	if (fakedma)
+	{
+		shm = (volatile dma_t*) Hunk_AllocName(sizeof(*shm), "shm");
+		shm->splitbuffer = 0;
+		shm->samplebits = 16;
+		shm->speed = 22050;
+		shm->channels = 2;
+		shm->samples = 32768;
+		shm->samplepos = 0;
+		shm->soundalive = true;
+		shm->gamealive = true;
+		shm->submission_chunk = 1;
+		shm->buffer = (unsigned char*) Hunk_AllocName(1<<16, "shmbuf");
+	}
+
+	if (shm)
+	{
+		Con_Printf ("Sound sampling rate: %i\n", shm->speed);
+	}
+	else
+	{
+		Con_Printf ("Sound sampling rate: undefined\n");
+	}
+
+	// provides a tick sound until washed clean
+
+//	if (shm->buffer)
+//		shm->buffer[4] = shm->buffer[5] = 0x7f;	// force a pop for debugging
+
+	ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");
+	ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");
+
+	S_StopAllSounds (true);
+}
+
+
+// =======================================================================
+// Shutdown sound engine
+// =======================================================================
+
+void S_Shutdown(void)
+{
+
+	if (!sound_started)
+		return;
+
+	if (shm)
+		shm->gamealive = 0;
+
+	shm = 0;
+	sound_started = 0;
+
+	if (!fakedma)
+	{
+		SNDDMA_Shutdown();
+	}
+}
+
+
+// =======================================================================
+// Load a sound
+// =======================================================================
+
+/*
+==================
+S_FindName
+
+==================
+*/
+sfx_t *S_FindName (const char *name)
+{
+	int		i;
+	sfx_t	*sfx;
+
+	if (!name)
+		Sys_Error ("S_FindName: NULL\n");
+
+	if (Q_strlen(name) >= MAX_QPATH)
+		Sys_Error ("Sound name too long: %s", name);
+
+// see if already loaded
+	for (i=0 ; i < num_sfx ; i++)
+		if (!Q_strcmp(known_sfx[i].name, name))
+		{
+			return &known_sfx[i];
+		}
+
+	if (num_sfx == MAX_SFX)
+		Sys_Error ("S_FindName: out of sfx_t");
+	
+	sfx = &known_sfx[i];
+	strcpy (sfx->name, name);
+
+	num_sfx++;
+	
+	return sfx;
+}
+
+
+/*
+==================
+S_TouchSound
+
+==================
+*/
+void S_TouchSound (const char *name)
+{
+	sfx_t	*sfx;
+	
+	if (!sound_started)
+		return;
+
+	sfx = S_FindName (name);
+	Cache_Check (&sfx->cache);
+}
+
+/*
+==================
+S_PrecacheSound
+
+==================
+*/
+sfx_t *S_PrecacheSound (const char *name)
+{
+	sfx_t	*sfx;
+
+	if (!sound_started || nosound.value)
+		return NULL;
+
+	sfx = S_FindName (name);
+	
+// cache it in
+	if (precache.value)
+		S_LoadSound (sfx);
+	
+	return sfx;
+}
+
+
+//=============================================================================
+
+/*
+=================
+SND_PickChannel
+=================
+*/
+channel_t *SND_PickChannel(int entnum, int entchannel)
+{
+    int ch_idx;
+    int first_to_die;
+    int life_left;
+
+// Check for replacement sound, or find the best one to replace
+    first_to_die = -1;
+    life_left = 0x7fffffff;
+    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
+    {
+		if (entchannel != 0		// channel 0 never overrides
+		&& channels[ch_idx].entnum == entnum
+		&& (channels[ch_idx].entchannel == entchannel || entchannel == -1) )
+		{	// allways override sound from same entity
+			first_to_die = ch_idx;
+			break;
+		}
+
+		// don't let monster sounds override player sounds
+		if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)
+			continue;
+
+		if (channels[ch_idx].end - paintedtime < life_left)
+		{
+			life_left = channels[ch_idx].end - paintedtime;
+			first_to_die = ch_idx;
+		}
+   }
+
+	if (first_to_die == -1)
+		return NULL;
+
+	if (channels[first_to_die].sfx)
+		channels[first_to_die].sfx = NULL;
+
+    return &channels[first_to_die];    
+}       
+
+/*
+=================
+SND_Spatialize
+=================
+*/
+void SND_Spatialize(channel_t *ch)
+{
+    vec_t dot;
+    vec_t ldist, rdist, dist;
+    vec_t lscale, rscale, scale;
+    vec3_t source_vec;
+	sfx_t *snd;
+
+// anything coming from the view entity will allways be full volume
+	if (ch->entnum == cl.viewentity)
+	{
+		ch->leftvol = ch->master_vol;
+		ch->rightvol = ch->master_vol;
+		return;
+	}
+
+// calculate stereo seperation and distance attenuation
+
+	snd = ch->sfx;
+	VectorSubtract(ch->origin, listener_origin, source_vec);
+	
+	dist = VectorNormalize(source_vec) * ch->dist_mult;
+	
+	dot = DotProduct(listener_right, source_vec);
+
+	if (shm->channels == 1)
+	{
+		rscale = 1.0;
+		lscale = 1.0;
+	}
+	else
+	{
+		rscale = 1.0 + dot;
+		lscale = 1.0 - dot;
+	}
+
+// add in distance effect
+	scale = (1.0 - dist) * rscale;
+	ch->rightvol = (int) (ch->master_vol * scale);
+	if (ch->rightvol < 0)
+		ch->rightvol = 0;
+
+	scale = (1.0 - dist) * lscale;
+	ch->leftvol = (int) (ch->master_vol * scale);
+	if (ch->leftvol < 0)
+		ch->leftvol = 0;
+}           
+
+
+// =======================================================================
+// Start a sound effect
+// =======================================================================
+
+void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
+{
+	channel_t *target_chan, *check;
+	sfxcache_t	*sc;
+	int		vol;
+	int		ch_idx;
+	int		skip;
+
+	if (!sound_started)
+		return;
+
+	if (!sfx)
+		return;
+
+	if (nosound.value)
+		return;
+
+	vol = (int)(fvol*255);
+
+// pick a channel to play on
+	target_chan = SND_PickChannel(entnum, entchannel);
+	if (!target_chan)
+		return;
+		
+// spatialize
+	memset (target_chan, 0, sizeof(*target_chan));
+	VectorCopy(origin, target_chan->origin);
+	target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
+	target_chan->master_vol = vol;
+	target_chan->entnum = entnum;
+	target_chan->entchannel = entchannel;
+	SND_Spatialize(target_chan);
+
+	if (!target_chan->leftvol && !target_chan->rightvol)
+		return;		// not audible at all
+
+// new channel
+	sc = S_LoadSound (sfx);
+	if (!sc)
+	{
+		target_chan->sfx = NULL;
+		return;		// couldn't load the sound's data
+	}
+
+	target_chan->sfx = sfx;
+	target_chan->pos = 0;
+    target_chan->end = paintedtime + sc->length;	
+
+// if an identical sound has also been started this frame, offset the pos
+// a bit to keep it from just making the first one louder
+	check = &channels[NUM_AMBIENTS];
+    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
+    {
+		if (check == target_chan)
+			continue;
+		if (check->sfx == sfx && !check->pos)
+		{
+			skip = rand () % (int)(0.1*shm->speed);
+			if (skip >= target_chan->end)
+				skip = target_chan->end - 1;
+			target_chan->pos += skip;
+			target_chan->end -= skip;
+			break;
+		}
+		
+	}
+}
+
+void S_StopSound(int entnum, int entchannel)
+{
+	int i;
+
+	for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)
+	{
+		if (channels[i].entnum == entnum
+			&& channels[i].entchannel == entchannel)
+		{
+			channels[i].end = 0;
+			channels[i].sfx = NULL;
+			return;
+		}
+	}
+}
+
+void S_StopAllSounds(qboolean clear)
+{
+	int		i;
+
+	if (!sound_started)
+		return;
+
+	total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;	// no statics
+
+	for (i=0 ; i<MAX_CHANNELS ; i++)
+		if (channels[i].sfx)
+			channels[i].sfx = NULL;
+
+	Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
+
+	if (clear)
+		S_ClearBuffer ();
+}
+
+void S_StopAllSoundsC (void)
+{
+	S_StopAllSounds (true);
+}
+
+void S_ClearBuffer (void)
+{
+	int		clear;
+		
+#ifdef _WIN32
+	if (!sound_started || !shm || (!shm->buffer && !pDSBuf))
+#else
+	if (!sound_started || !shm || !shm->buffer)
+#endif
+		return;
+
+	if (shm->samplebits == 8)
+		clear = 0x80;
+	else
+		clear = 0;
+
+#ifdef _WIN32
+	if (pDSBuf)
+	{
+		DWORD	dwSize;
+		DWORD	*pData;
+		int		reps;
+		HRESULT	hresult;
+
+		reps = 0;
+
+		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK)
+		{
+			if (hresult != DSERR_BUFFERLOST)
+			{
+				Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");
+				S_Shutdown ();
+				return;
+			}
+
+			if (++reps > 10000)
+			{
+				Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n");
+				S_Shutdown ();
+				return;
+			}
+		}
+
+		Q_memset(pData, clear, shm->samples * shm->samplebits/8);
+
+		pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);
+	
+	}
+	else
+#endif
+	{
+		Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8);
+	}
+}
+
+
+/*
+=================
+S_StaticSound
+=================
+*/
+void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
+{
+	channel_t	*ss;
+	sfxcache_t		*sc;
+
+	if (!sfx)
+		return;
+
+	if (total_channels == MAX_CHANNELS)
+	{
+		Con_Printf ("total_channels == MAX_CHANNELS\n");
+		return;
+	}
+
+	ss = &channels[total_channels];
+	total_channels++;
+
+	sc = S_LoadSound (sfx);
+	if (!sc)
+		return;
+
+	if (sc->loopstart == -1)
+	{
+		Con_Printf ("Sound %s not looped\n", sfx->name);
+		return;
+	}
+	
+	ss->sfx = sfx;
+	VectorCopy (origin, ss->origin);
+	ss->master_vol = (int) vol;
+	ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
+    ss->end = paintedtime + sc->length;	
+	
+	SND_Spatialize (ss);
+}
+
+
+//=============================================================================
+
+/*
+===================
+S_UpdateAmbientSounds
+===================
+*/
+void S_UpdateAmbientSounds (void)
+{
+	mleaf_t		*l;
+	float		vol;
+	int			ambient_channel;
+	channel_t	*chan;
+
+	if (!snd_ambient)
+		return;
+
+// calc ambient sound levels
+	if (!cl.worldmodel)
+		return;
+
+	l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
+	if (!l || !ambient_level.value)
+	{
+		for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
+			channels[ambient_channel].sfx = NULL;
+		return;
+	}
+
+	for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
+	{
+		chan = &channels[ambient_channel];	
+		chan->sfx = ambient_sfx[ambient_channel];
+	
+		vol = ambient_level.value * l->ambient_sound_level[ambient_channel];
+		if (vol < 8)
+			vol = 0;
+
+	// don't adjust volume too fast
+		if (chan->master_vol < vol)
+		{
+			chan->master_vol += (int) (host_frametime * ambient_fade.value);
+			if (chan->master_vol > vol)
+				chan->master_vol = (int) vol;
+		}
+		else if (chan->master_vol > vol)
+		{
+			chan->master_vol -= (int) (host_frametime * ambient_fade.value);
+			if (chan->master_vol < vol)
+				chan->master_vol = (int) vol;
+		}
+		
+		chan->leftvol = chan->rightvol = chan->master_vol;
+	}
+}
+
+
+/*
+============
+S_Update
+
+Called once each time through the main loop
+============
+*/
+void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
+{
+	int			i, j;
+	int			total;
+	channel_t	*ch;
+	channel_t	*combine;
+
+	if (!sound_started || (snd_blocked > 0))
+		return;
+
+	VectorCopy(origin, listener_origin);
+	VectorCopy(forward, listener_forward);
+	VectorCopy(right, listener_right);
+	VectorCopy(up, listener_up);
+	
+// update general area ambient sound sources
+	S_UpdateAmbientSounds ();
+
+	combine = NULL;
+
+// update spatialization for static and dynamic sounds	
+	ch = channels+NUM_AMBIENTS;
+	for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
+	{
+		if (!ch->sfx)
+			continue;
+		SND_Spatialize(ch);         // respatialize channel
+		if (!ch->leftvol && !ch->rightvol)
+			continue;
+
+	// try to combine static sounds with a previous channel of the same
+	// sound effect so we don't mix five torches every frame
+	
+		if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
+		{
+		// see if it can just use the last one
+			if (combine && combine->sfx == ch->sfx)
+			{
+				combine->leftvol += ch->leftvol;
+				combine->rightvol += ch->rightvol;
+				ch->leftvol = ch->rightvol = 0;
+				continue;
+			}
+		// search for one
+			combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
+			for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
+				if (combine->sfx == ch->sfx)
+					break;
+					
+			if (j == total_channels)
+			{
+				combine = NULL;
+			}
+			else
+			{
+				if (combine != ch)
+				{
+					combine->leftvol += ch->leftvol;
+					combine->rightvol += ch->rightvol;
+					ch->leftvol = ch->rightvol = 0;
+				}
+				continue;
+			}
+		}
+		
+		
+	}
+
+//
+// debugging output
+//
+	if (snd_show.value)
+	{
+		total = 0;
+		ch = channels;
+		for (i=0 ; i<total_channels; i++, ch++)
+			if (ch->sfx && (ch->leftvol || ch->rightvol) )
+			{
+				//Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
+				total++;
+			}
+		
+		Con_Printf ("----(%i)----\n", total);
+	}
+
+// mix some sound
+	S_Update_();
+}
+
+void GetSoundtime(void)
+{
+	int		samplepos;
+	static	int		buffers;
+	static	int		oldsamplepos;
+	int		fullsamples;
+	
+	fullsamples = shm->samples / shm->channels;
+
+// it is possible to miscount buffers if it has wrapped twice between
+// calls to S_Update.  Oh well.
+#ifdef __sun__
+	soundtime = SNDDMA_GetSamples();
+#else
+	samplepos = SNDDMA_GetDMAPos();
+
+
+	if (samplepos < oldsamplepos)
+	{
+		buffers++;					// buffer wrapped
+		
+		if (paintedtime > 0x40000000)
+		{	// time to chop things off to avoid 32 bit limits
+			buffers = 0;
+			paintedtime = fullsamples;
+			S_StopAllSounds (true);
+		}
+	}
+	oldsamplepos = samplepos;
+
+	soundtime = buffers*fullsamples + samplepos/shm->channels;
+#endif
+}
+
+void S_ExtraUpdate (void)
+{
+
+#ifdef _WIN32
+	IN_Accumulate ();
+#endif
+
+	if (snd_noextraupdate.value)
+		return;		// don't pollute timings
+	S_Update_();
+}
+
+void S_Update_(void)
+{
+	unsigned        endtime;
+	int				samps;
+	
+	if (!sound_started || (snd_blocked > 0))
+		return;
+
+// Updates DMA time
+	GetSoundtime();
+
+// check to make sure that we haven't overshot
+	if (paintedtime < soundtime)
+	{
+		//Con_Printf ("S_Update_ : overflow\n");
+		paintedtime = soundtime;
+	}
+
+// mix ahead of current position
+	endtime = (unsigned) (soundtime + _snd_mixahead.value * shm->speed);
+	samps = shm->samples >> (shm->channels-1);
+	if ((int) (endtime - soundtime) > samps)
+		endtime = soundtime + samps;
+
+#ifdef _WIN32
+// if the buffer was lost or stopped, restore it and/or restart it
+	{
+		DWORD	dwStatus;
+
+		if (pDSBuf)
+		{
+			if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)
+				Con_Printf ("Couldn't get sound buffer status\n");
+			
+			if (dwStatus & DSBSTATUS_BUFFERLOST)
+				pDSBuf->lpVtbl->Restore (pDSBuf);
+			
+			if (!(dwStatus & DSBSTATUS_PLAYING))
+				pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
+		}
+	}
+#endif
+
+	S_PaintChannels (endtime);
+
+	SNDDMA_Submit ();
+}
+
+/*
+===============================================================================
+
+console functions
+
+===============================================================================
+*/
+
+void S_Play(void)
+{
+	static int hash=345;
+	int 	i;
+	char name[256];
+	sfx_t	*sfx;
+	
+	i = 1;
+	while (i<Cmd_Argc())
+	{
+		if (!Q_strrchr(Cmd_Argv(i), '.'))
+		{
+			Q_strcpy(name, Cmd_Argv(i));
+			Q_strcat(name, ".wav");
+		}
+		else
+			Q_strcpy(name, Cmd_Argv(i));
+		sfx = S_PrecacheSound(name);
+		S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);
+		i++;
+	}
+}
+
+void S_PlayVol(void)
+{
+	static int hash=543;
+	int i;
+	float vol;
+	char name[256];
+	sfx_t	*sfx;
+	
+	i = 1;
+	while (i<Cmd_Argc())
+	{
+		if (!Q_strrchr(Cmd_Argv(i), '.'))
+		{
+			Q_strcpy(name, Cmd_Argv(i));
+			Q_strcat(name, ".wav");
+		}
+		else
+			Q_strcpy(name, Cmd_Argv(i));
+		sfx = S_PrecacheSound(name);
+		vol = Q_atof(Cmd_Argv(i+1));
+		S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);
+		i+=2;
+	}
+}
+
+void S_SoundList(void)
+{
+	int		i;
+	sfx_t	*sfx;
+	sfxcache_t	*sc;
+	int		size, total;
+
+	total = 0;
+	for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
+	{
+		sc = (sfxcache_t*) Cache_Check (&sfx->cache);
+		if (!sc)
+			continue;
+		size = sc->length*sc->width*(sc->stereo+1);
+		total += size;
+		if (sc->loopstart >= 0)
+			Con_Printf ("L");
+		else
+			Con_Printf (" ");
+		Con_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);
+	}
+	Con_Printf ("Total resident: %i\n", total);
+}
+
+
+void S_LocalSound (const char *sound)
+{
+	sfx_t	*sfx;
+
+	if (nosound.value)
+		return;
+	if (!sound_started)
+		return;
+		
+	sfx = S_PrecacheSound (sound);
+	if (!sfx)
+	{
+		Con_Printf ("S_LocalSound: can't cache %s\n", sound);
+		return;
+	}
+	S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);
+}
+
+
+void S_ClearPrecache (void)
+{
+}
+
+
+void S_BeginPrecaching (void)
+{
+}
+
+
+void S_EndPrecaching (void)
+{
+}
+
diff --git a/quake/src/WinQuake/snd_dos.c b/quake/src/WinQuake/snd_dos.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/snd_dos.c
rename to quake/src/WinQuake/snd_dos.cpp
diff --git a/quake/src/WinQuake/snd_gus.c b/quake/src/WinQuake/snd_gus.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/snd_gus.c
rename to quake/src/WinQuake/snd_gus.cpp
diff --git a/quake/src/WinQuake/snd_linux.c b/quake/src/WinQuake/snd_linux.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/snd_linux.c
rename to quake/src/WinQuake/snd_linux.cpp
diff --git a/quake/src/WinQuake/snd_mem.c b/quake/src/WinQuake/snd_mem.cpp
old mode 100644
new mode 100755
similarity index 89%
rename from quake/src/WinQuake/snd_mem.c
rename to quake/src/WinQuake/snd_mem.cpp
index 494928a..b89e553
--- a/quake/src/WinQuake/snd_mem.c
+++ b/quake/src/WinQuake/snd_mem.cpp
@@ -1,341 +1,341 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// snd_mem.c: sound caching

-

-#include "quakedef.h"

-

-int			cache_full_cycle;

-

-byte *S_Alloc (int size);

-

-/*

-================

-ResampleSfx

-================

-*/

-void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)

-{

-	int		outcount;

-	int		srcsample;

-	float	stepscale;

-	int		i;

-	int		sample, samplefrac, fracstep;

-	sfxcache_t	*sc;

-	

-	sc = Cache_Check (&sfx->cache);

-	if (!sc)

-		return;

-

-	stepscale = (float)inrate / shm->speed;	// this is usually 0.5, 1, or 2

-

-	outcount = sc->length / stepscale;

-	sc->length = outcount;

-	if (sc->loopstart != -1)

-		sc->loopstart = sc->loopstart / stepscale;

-

-	sc->speed = shm->speed;

-	if (loadas8bit.value)

-		sc->width = 1;

-	else

-		sc->width = inwidth;

-	sc->stereo = 0;

-

-// resample / decimate to the current source rate

-

-	if (stepscale == 1 && inwidth == 1 && sc->width == 1)

-	{

-// fast special case

-		for (i=0 ; i<outcount ; i++)

-			((signed char *)sc->data)[i]

-			= (int)( (unsigned char)(data[i]) - 128);

-	}

-	else

-	{

-// general case

-		samplefrac = 0;

-		fracstep = stepscale*256;

-		for (i=0 ; i<outcount ; i++)

-		{

-			srcsample = samplefrac >> 8;

-			samplefrac += fracstep;

-			if (inwidth == 2)

-				sample = LittleShort ( ((short *)data)[srcsample] );

-			else

-				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;

-			if (sc->width == 2)

-				((short *)sc->data)[i] = sample;

-			else

-				((signed char *)sc->data)[i] = sample >> 8;

-		}

-	}

-}

-

-//=============================================================================

-

-/*

-==============

-S_LoadSound

-==============

-*/

-sfxcache_t *S_LoadSound (sfx_t *s)

-{

-    char	namebuffer[256];

-	byte	*data;

-	wavinfo_t	info;

-	int		len;

-	float	stepscale;

-	sfxcache_t	*sc;

-	byte	stackbuf[1*1024];		// avoid dirtying the cache heap

-

-// see if still in memory

-	sc = Cache_Check (&s->cache);

-	if (sc)

-		return sc;

-

-//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);

-// load it in

-    Q_strcpy(namebuffer, "sound/");

-    Q_strcat(namebuffer, s->name);

-

-//	Con_Printf ("loading %s\n",namebuffer);

-

-	data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));

-

-	if (!data)

-	{

-		Con_Printf ("Couldn't load %s\n", namebuffer);

-		return NULL;

-	}

-

-	info = GetWavinfo (s->name, data, com_filesize);

-	if (info.channels != 1)

-	{

-		Con_Printf ("%s is a stereo sample\n",s->name);

-		return NULL;

-	}

-

-	stepscale = (float)info.rate / shm->speed;	

-	len = info.samples / stepscale;

-

-	len = len * info.width * info.channels;

-

-	sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);

-	if (!sc)

-		return NULL;

-	

-	sc->length = info.samples;

-	sc->loopstart = info.loopstart;

-	sc->speed = info.rate;

-	sc->width = info.width;

-	sc->stereo = info.channels;

-

-	ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);

-

-	return sc;

-}

-

-

-

-/*

-===============================================================================

-

-WAV loading

-

-===============================================================================

-*/

-

-

-byte	*data_p;

-byte 	*iff_end;

-byte 	*last_chunk;

-byte 	*iff_data;

-int 	iff_chunk_len;

-

-

-short GetLittleShort(void)

-{

-	short val = 0;

-	val = *data_p;

-	val = val + (*(data_p+1)<<8);

-	data_p += 2;

-	return val;

-}

-

-int GetLittleLong(void)

-{

-	int val = 0;

-	val = *data_p;

-	val = val + (*(data_p+1)<<8);

-	val = val + (*(data_p+2)<<16);

-	val = val + (*(data_p+3)<<24);

-	data_p += 4;

-	return val;

-}

-

-void FindNextChunk(char *name)

-{

-	while (1)

-	{

-		data_p=last_chunk;

-

-		if (data_p >= iff_end)

-		{	// didn't find the chunk

-			data_p = NULL;

-			return;

-		}

-		

-		data_p += 4;

-		iff_chunk_len = GetLittleLong();

-		if (iff_chunk_len < 0)

-		{

-			data_p = NULL;

-			return;

-		}

-//		if (iff_chunk_len > 1024*1024)

-//			Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);

-		data_p -= 8;

-		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );

-		if (!Q_strncmp(data_p, name, 4))

-			return;

-	}

-}

-

-void FindChunk(char *name)

-{

-	last_chunk = iff_data;

-	FindNextChunk (name);

-}

-

-

-void DumpChunks(void)

-{

-	char	str[5];

-	

-	str[4] = 0;

-	data_p=iff_data;

-	do

-	{

-		memcpy (str, data_p, 4);

-		data_p += 4;

-		iff_chunk_len = GetLittleLong();

-		Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);

-		data_p += (iff_chunk_len + 1) & ~1;

-	} while (data_p < iff_end);

-}

-

-/*

-============

-GetWavinfo

-============

-*/

-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)

-{

-	wavinfo_t	info;

-	int     i;

-	int     format;

-	int		samples;

-

-	memset (&info, 0, sizeof(info));

-

-	if (!wav)

-		return info;

-		

-	iff_data = wav;

-	iff_end = wav + wavlength;

-

-// find "RIFF" chunk

-	FindChunk("RIFF");

-	if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))

-	{

-		Con_Printf("Missing RIFF/WAVE chunks\n");

-		return info;

-	}

-

-// get "fmt " chunk

-	iff_data = data_p + 12;

-// DumpChunks ();

-

-	FindChunk("fmt ");

-	if (!data_p)

-	{

-		Con_Printf("Missing fmt chunk\n");

-		return info;

-	}

-	data_p += 8;

-	format = GetLittleShort();

-	if (format != 1)

-	{

-		Con_Printf("Microsoft PCM format only\n");

-		return info;

-	}

-

-	info.channels = GetLittleShort();

-	info.rate = GetLittleLong();

-	data_p += 4+2;

-	info.width = GetLittleShort() / 8;

-

-// get cue chunk

-	FindChunk("cue ");

-	if (data_p)

-	{

-		data_p += 32;

-		info.loopstart = GetLittleLong();

-//		Con_Printf("loopstart=%d\n", sfx->loopstart);

-

-	// if the next chunk is a LIST chunk, look for a cue length marker

-		FindNextChunk ("LIST");

-		if (data_p)

-		{

-			if (!strncmp (data_p + 28, "mark", 4))

-			{	// this is not a proper parse, but it works with cooledit...

-				data_p += 24;

-				i = GetLittleLong ();	// samples in loop

-				info.samples = info.loopstart + i;

-//				Con_Printf("looped length: %i\n", i);

-			}

-		}

-	}

-	else

-		info.loopstart = -1;

-

-// find data chunk

-	FindChunk("data");

-	if (!data_p)

-	{

-		Con_Printf("Missing data chunk\n");

-		return info;

-	}

-

-	data_p += 4;

-	samples = GetLittleLong () / info.width;

-

-	if (info.samples)

-	{

-		if (samples < info.samples)

-			Sys_Error ("Sound %s has a bad loop length", name);

-	}

-	else

-		info.samples = samples;

-

-	info.dataofs = data_p - wav;

-	

-	return info;

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// snd_mem.c: sound caching
+
+#include "quakedef.h"
+
+int			cache_full_cycle;
+
+byte *S_Alloc (int size);
+
+/*
+================
+ResampleSfx
+================
+*/
+void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
+{
+	int		outcount;
+	int		srcsample;
+	float	stepscale;
+	int		i;
+	int		sample, samplefrac, fracstep;
+	sfxcache_t	*sc;
+	
+	sc = (sfxcache_t*) Cache_Check (&sfx->cache);
+	if (!sc)
+		return;
+
+	stepscale = (float)inrate / shm->speed;	// this is usually 0.5, 1, or 2
+
+	outcount = (int) (sc->length / stepscale);
+	sc->length = outcount;
+	if (sc->loopstart != -1)
+		sc->loopstart = (int) (sc->loopstart / stepscale);
+
+	sc->speed = shm->speed;
+	if (loadas8bit.value)
+		sc->width = 1;
+	else
+		sc->width = inwidth;
+	sc->stereo = 0;
+
+// resample / decimate to the current source rate
+
+	if (stepscale == 1 && inwidth == 1 && sc->width == 1)
+	{
+// fast special case
+		for (i=0 ; i<outcount ; i++)
+			sc->data.sc[i]
+			= (int)( (unsigned char)(data[i]) - 128);
+	}
+	else
+	{
+// general case
+		samplefrac = 0;
+		fracstep = (int) (stepscale*256);
+		for (i=0 ; i<outcount ; i++)
+		{
+			srcsample = samplefrac >> 8;
+			samplefrac += fracstep;
+			if (inwidth == 2)
+				sample = LittleShort ( ((short *)data)[srcsample] );
+			else
+				sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
+			if (sc->width == 2)
+				sc->data.s[i] = sample;
+			else
+				sc->data.sc[i] = sample >> 8;
+		}
+	}
+}
+
+//=============================================================================
+
+/*
+==============
+S_LoadSound
+==============
+*/
+sfxcache_t *S_LoadSound (sfx_t *s)
+{
+    char	namebuffer[256];
+	byte	*data;
+	wavinfo_t	info;
+	int		len;
+	float	stepscale;
+	sfxcache_t	*sc;
+	byte	stackbuf[1*1024];		// avoid dirtying the cache heap
+
+// see if still in memory
+	sc = (sfxcache_t*) Cache_Check (&s->cache);
+	if (sc)
+		return sc;
+
+//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
+// load it in
+    Q_strcpy(namebuffer, "sound/");
+    Q_strcat(namebuffer, s->name);
+
+//	Con_Printf ("loading %s\n",namebuffer);
+
+	data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
+
+	if (!data)
+	{
+		Con_Printf ("Couldn't load %s\n", namebuffer);
+		return NULL;
+	}
+
+	info = GetWavinfo (s->name, data, com_filesize);
+	if (info.channels != 1)
+	{
+		Con_Printf ("%s is a stereo sample\n",s->name);
+		return NULL;
+	}
+
+	stepscale = (float)info.rate / shm->speed;	
+	len = (int) (info.samples / stepscale);
+
+	len = len * info.width * info.channels;
+
+	sc = (sfxcache_t*) Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
+	if (!sc)
+		return NULL;
+	
+	sc->length = info.samples;
+	sc->loopstart = info.loopstart;
+	sc->speed = info.rate;
+	sc->width = info.width;
+	sc->stereo = info.channels;
+
+	ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
+
+	return sc;
+}
+
+
+
+/*
+===============================================================================
+
+WAV loading
+
+===============================================================================
+*/
+
+
+byte	*data_p;
+byte 	*iff_end;
+byte 	*last_chunk;
+byte 	*iff_data;
+int 	iff_chunk_len;
+
+
+short GetLittleShort(void)
+{
+	short val = 0;
+	val = *data_p;
+	val = val + (*(data_p+1)<<8);
+	data_p += 2;
+	return val;
+}
+
+int GetLittleLong(void)
+{
+	int val = 0;
+	val = *data_p;
+	val = val + (*(data_p+1)<<8);
+	val = val + (*(data_p+2)<<16);
+	val = val + (*(data_p+3)<<24);
+	data_p += 4;
+	return val;
+}
+
+void FindNextChunk(const char *name)
+{
+	while (1)
+	{
+		data_p=last_chunk;
+
+		if (data_p >= iff_end)
+		{	// didn't find the chunk
+			data_p = NULL;
+			return;
+		}
+		
+		data_p += 4;
+		iff_chunk_len = GetLittleLong();
+		if (iff_chunk_len < 0)
+		{
+			data_p = NULL;
+			return;
+		}
+//		if (iff_chunk_len > 1024*1024)
+//			Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
+		data_p -= 8;
+		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
+		if (!Q_strncmp((char*) data_p, name, 4))
+			return;
+	}
+}
+
+void FindChunk(const char *name)
+{
+	last_chunk = iff_data;
+	FindNextChunk (name);
+}
+
+
+void DumpChunks(void)
+{
+	char	str[5];
+	
+	str[4] = 0;
+	data_p=iff_data;
+	do
+	{
+		memcpy (str, data_p, 4);
+		data_p += 4;
+		iff_chunk_len = GetLittleLong();
+		Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
+		data_p += (iff_chunk_len + 1) & ~1;
+	} while (data_p < iff_end);
+}
+
+/*
+============
+GetWavinfo
+============
+*/
+wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
+{
+	wavinfo_t	info;
+	int     i;
+	int     format;
+	int		samples;
+
+	memset (&info, 0, sizeof(info));
+
+	if (!wav)
+		return info;
+		
+	iff_data = wav;
+	iff_end = wav + wavlength;
+
+// find "RIFF" chunk
+	FindChunk("RIFF");
+	if (!(data_p && !Q_strncmp((char*) (data_p+8), "WAVE", 4)))
+	{
+		Con_Printf("Missing RIFF/WAVE chunks\n");
+		return info;
+	}
+
+// get "fmt " chunk
+	iff_data = data_p + 12;
+// DumpChunks ();
+
+	FindChunk("fmt ");
+	if (!data_p)
+	{
+		Con_Printf("Missing fmt chunk\n");
+		return info;
+	}
+	data_p += 8;
+	format = GetLittleShort();
+	if (format != 1)
+	{
+		Con_Printf("Microsoft PCM format only\n");
+		return info;
+	}
+
+	info.channels = GetLittleShort();
+	info.rate = GetLittleLong();
+	data_p += 4+2;
+	info.width = GetLittleShort() / 8;
+
+// get cue chunk
+	FindChunk("cue ");
+	if (data_p)
+	{
+		data_p += 32;
+		info.loopstart = GetLittleLong();
+//		Con_Printf("loopstart=%d\n", sfx->loopstart);
+
+	// if the next chunk is a LIST chunk, look for a cue length marker
+		FindNextChunk ("LIST");
+		if (data_p)
+		{
+			if (!strncmp ((char*) (data_p + 28), "mark", 4))
+			{	// this is not a proper parse, but it works with cooledit...
+				data_p += 24;
+				i = GetLittleLong ();	// samples in loop
+				info.samples = info.loopstart + i;
+//				Con_Printf("looped length: %i\n", i);
+			}
+		}
+	}
+	else
+		info.loopstart = -1;
+
+// find data chunk
+	FindChunk("data");
+	if (!data_p)
+	{
+		Con_Printf("Missing data chunk\n");
+		return info;
+	}
+
+	data_p += 4;
+	samples = GetLittleLong () / info.width;
+
+	if (info.samples)
+	{
+		if (samples < info.samples)
+			Sys_Error ("Sound %s has a bad loop length", name);
+	}
+	else
+		info.samples = samples;
+
+	info.dataofs = data_p - wav;
+	
+	return info;
+}
+
diff --git a/quake/src/WinQuake/snd_mix.c b/quake/src/WinQuake/snd_mix.cpp
old mode 100644
new mode 100755
similarity index 90%
rename from quake/src/WinQuake/snd_mix.c
rename to quake/src/WinQuake/snd_mix.cpp
index c040494..1f16a13
--- a/quake/src/WinQuake/snd_mix.c
+++ b/quake/src/WinQuake/snd_mix.cpp
@@ -1,398 +1,406 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// snd_mix.c -- portable code to mix sounds for snd_dma.c

-

-#include "quakedef.h"

-

-#ifdef _WIN32

-#include "winquake.h"

-#else

-#define DWORD	unsigned long

-#endif

-

-#define	PAINTBUFFER_SIZE	512

-portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];

-int		snd_scaletable[32][256];

-int 	*snd_p, snd_linear_count, snd_vol;

-short	*snd_out;

-

-void Snd_WriteLinearBlastStereo16 (void);

-

-#if	!id386

-void Snd_WriteLinearBlastStereo16 (void)

-{

-	int		i;

-	int		val;

-

-	for (i=0 ; i<snd_linear_count ; i+=2)

-	{

-		val = (snd_p[i]*snd_vol)>>8;

-		if (val > 0x7fff)

-			snd_out[i] = 0x7fff;

-		else if (val < (short)0x8000)

-			snd_out[i] = (short)0x8000;

-		else

-			snd_out[i] = val;

-

-		val = (snd_p[i+1]*snd_vol)>>8;

-		if (val > 0x7fff)

-			snd_out[i+1] = 0x7fff;

-		else if (val < (short)0x8000)

-			snd_out[i+1] = (short)0x8000;

-		else

-			snd_out[i+1] = val;

-	}

-}

-#endif

-

-void S_TransferStereo16 (int endtime)

-{

-	int		lpos;

-	int		lpaintedtime;

-	DWORD	*pbuf;

-#ifdef _WIN32

-	int		reps;

-	DWORD	dwSize,dwSize2;

-	DWORD	*pbuf2;

-	HRESULT	hresult;

-#endif

-	

-	snd_vol = volume.value*256;

-

-	snd_p = (int *) paintbuffer;

-	lpaintedtime = paintedtime;

-

-#ifdef _WIN32

-	if (pDSBuf)

-	{

-		reps = 0;

-

-		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 

-									   &pbuf2, &dwSize2, 0)) != DS_OK)

-		{

-			if (hresult != DSERR_BUFFERLOST)

-			{

-				Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");

-				S_Shutdown ();

-				S_Startup ();

-				return;

-			}

-

-			if (++reps > 10000)

-			{

-				Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");

-				S_Shutdown ();

-				S_Startup ();

-				return;

-			}

-		}

-	}

-	else

-#endif

-	{

-		pbuf = (DWORD *)shm->buffer;

-	}

-

-	while (lpaintedtime < endtime)

-	{

-	// handle recirculating buffer issues

-		lpos = lpaintedtime & ((shm->samples>>1)-1);

-

-		snd_out = (short *) pbuf + (lpos<<1);

-

-		snd_linear_count = (shm->samples>>1) - lpos;

-		if (lpaintedtime + snd_linear_count > endtime)

-			snd_linear_count = endtime - lpaintedtime;

-

-		snd_linear_count <<= 1;

-

-	// write a linear blast of samples

-		Snd_WriteLinearBlastStereo16 ();

-

-		snd_p += snd_linear_count;

-		lpaintedtime += (snd_linear_count>>1);

-	}

-

-#ifdef _WIN32

-	if (pDSBuf)

-		pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);

-#endif

-}

-

-void S_TransferPaintBuffer(int endtime)

-{

-	int 	out_idx;

-	int 	count;

-	int 	out_mask;

-	int 	*p;

-	int 	step;

-	int		val;

-	int		snd_vol;

-	DWORD	*pbuf;

-#ifdef _WIN32

-	int		reps;

-	DWORD	dwSize,dwSize2;

-	DWORD	*pbuf2;

-	HRESULT	hresult;

-#endif

-

-	if (shm->samplebits == 16 && shm->channels == 2)

-	{

-		S_TransferStereo16 (endtime);

-		return;

-	}

-	

-	p = (int *) paintbuffer;

-	count = (endtime - paintedtime) * shm->channels;

-	out_mask = shm->samples - 1; 

-	out_idx = paintedtime * shm->channels & out_mask;

-	step = 3 - shm->channels;

-	snd_vol = volume.value*256;

-

-#ifdef _WIN32

-	if (pDSBuf)

-	{

-		reps = 0;

-

-		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 

-									   &pbuf2,&dwSize2, 0)) != DS_OK)

-		{

-			if (hresult != DSERR_BUFFERLOST)

-			{

-				Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");

-				S_Shutdown ();

-				S_Startup ();

-				return;

-			}

-

-			if (++reps > 10000)

-			{

-				Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");

-				S_Shutdown ();

-				S_Startup ();

-				return;

-			}

-		}

-	}

-	else

-#endif

-	{

-		pbuf = (DWORD *)shm->buffer;

-	}

-

-	if (shm->samplebits == 16)

-	{

-		short *out = (short *) pbuf;

-		while (count--)

-		{

-			val = (*p * snd_vol) >> 8;

-			p+= step;

-			if (val > 0x7fff)

-				val = 0x7fff;

-			else if (val < (short)0x8000)

-				val = (short)0x8000;

-			out[out_idx] = val;

-			out_idx = (out_idx + 1) & out_mask;

-		}

-	}

-	else if (shm->samplebits == 8)

-	{

-		unsigned char *out = (unsigned char *) pbuf;

-		while (count--)

-		{

-			val = (*p * snd_vol) >> 8;

-			p+= step;

-			if (val > 0x7fff)

-				val = 0x7fff;

-			else if (val < (short)0x8000)

-				val = (short)0x8000;

-			out[out_idx] = (val>>8) + 128;

-			out_idx = (out_idx + 1) & out_mask;

-		}

-	}

-

-#ifdef _WIN32

-	if (pDSBuf) {

-		DWORD dwNewpos, dwWrite;

-		int il = paintedtime;

-		int ir = endtime - paintedtime;

-		

-		ir += il;

-

-		pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);

-

-		pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);

-

-//		if ((dwNewpos >= il) && (dwNewpos <= ir))

-//			Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);

-	}

-#endif

-}

-

-

-/*

-===============================================================================

-

-CHANNEL MIXING

-

-===============================================================================

-*/

-

-void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);

-void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);

-

-void S_PaintChannels(int endtime)

-{

-	int 	i;

-	int 	end;

-	channel_t *ch;

-	sfxcache_t	*sc;

-	int		ltime, count;

-

-	while (paintedtime < endtime)

-	{

-	// if paintbuffer is smaller than DMA buffer

-		end = endtime;

-		if (endtime - paintedtime > PAINTBUFFER_SIZE)

-			end = paintedtime + PAINTBUFFER_SIZE;

-

-	// clear the paint buffer

-		Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));

-

-	// paint in the channels.

-		ch = channels;

-		for (i=0; i<total_channels ; i++, ch++)

-		{

-			if (!ch->sfx)

-				continue;

-			if (!ch->leftvol && !ch->rightvol)

-				continue;

-			sc = S_LoadSound (ch->sfx);

-			if (!sc)

-				continue;

-

-			ltime = paintedtime;

-

-			while (ltime < end)

-			{	// paint up to end

-				if (ch->end < end)

-					count = ch->end - ltime;

-				else

-					count = end - ltime;

-

-				if (count > 0)

-				{	

-					if (sc->width == 1)

-						SND_PaintChannelFrom8(ch, sc, count);

-					else

-						SND_PaintChannelFrom16(ch, sc, count);

-	

-					ltime += count;

-				}

-

-			// if at end of loop, restart

-				if (ltime >= ch->end)

-				{

-					if (sc->loopstart >= 0)

-					{

-						ch->pos = sc->loopstart;

-						ch->end = ltime + sc->length - ch->pos;

-					}

-					else				

-					{	// channel just stopped

-						ch->sfx = NULL;

-						break;

-					}

-				}

-			}

-															  

-		}

-

-	// transfer out according to DMA format

-		S_TransferPaintBuffer(end);

-		paintedtime = end;

-	}

-}

-

-void SND_InitScaletable (void)

-{

-	int		i, j;

-	

-	for (i=0 ; i<32 ; i++)

-		for (j=0 ; j<256 ; j++)

-			snd_scaletable[i][j] = ((signed char)j) * i * 8;

-}

-

-

-#if	!id386

-

-void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)

-{

-	int 	data;

-	int		*lscale, *rscale;

-	unsigned char *sfx;

-	int		i;

-

-	if (ch->leftvol > 255)

-		ch->leftvol = 255;

-	if (ch->rightvol > 255)

-		ch->rightvol = 255;

-		

-	lscale = snd_scaletable[ch->leftvol >> 3];

-	rscale = snd_scaletable[ch->rightvol >> 3];

-	sfx = (signed char *)sc->data + ch->pos;

-

-	for (i=0 ; i<count ; i++)

-	{

-		data = sfx[i];

-		paintbuffer[i].left += lscale[data];

-		paintbuffer[i].right += rscale[data];

-	}

-	

-	ch->pos += count;

-}

-

-#endif	// !id386

-

-

-void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)

-{

-	int data;

-	int left, right;

-	int leftvol, rightvol;

-	signed short *sfx;

-	int	i;

-

-	leftvol = ch->leftvol;

-	rightvol = ch->rightvol;

-	sfx = (signed short *)sc->data + ch->pos;

-

-	for (i=0 ; i<count ; i++)

-	{

-		data = sfx[i];

-		left = (data * leftvol) >> 8;

-		right = (data * rightvol) >> 8;

-		paintbuffer[i].left += left;

-		paintbuffer[i].right += right;

-	}

-

-	ch->pos += count;

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// snd_mix.c -- portable code to mix sounds for snd_dma.c
+
+#include "quakedef.h"
+
+#ifdef _WIN32
+#include "winquake.h"
+#else
+#define DWORD	unsigned long
+#endif
+
+#define	PAINTBUFFER_SIZE	512
+
+typedef union {
+    portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
+    int intbuf[PAINTBUFFER_SIZE * sizeof(portable_samplepair_t) / sizeof(int)];
+} portableOrInt_t;
+
+portableOrInt_t paintbuffer;
+int		snd_scaletable[32][256];
+int 	*snd_p, snd_linear_count, snd_vol;
+short	*snd_out;
+
+void Snd_WriteLinearBlastStereo16 (void);
+
+extern void SNDDMA_ReportWrite(size_t lengthBytes);
+#if	!id386
+void Snd_WriteLinearBlastStereo16 (void)
+{
+	int		i;
+	int		val;
+
+	for (i=0 ; i<snd_linear_count ; i+=2)
+	{
+		val = (snd_p[i]*snd_vol)>>8;
+		if (val > 0x7fff)
+			snd_out[i] = 0x7fff;
+		else if (val < (short)0x8000)
+			snd_out[i] = (short)0x8000;
+		else
+			snd_out[i] = val;
+
+		val = (snd_p[i+1]*snd_vol)>>8;
+		if (val > 0x7fff)
+			snd_out[i+1] = 0x7fff;
+		else if (val < (short)0x8000)
+			snd_out[i+1] = (short)0x8000;
+		else
+			snd_out[i+1] = val;
+	}
+	SNDDMA_ReportWrite(snd_linear_count << 1);
+}
+#endif
+
+void S_TransferStereo16 (int endtime)
+{
+	int		lpos;
+	int		lpaintedtime;
+	DWORD	*pbuf;
+#ifdef _WIN32
+	int		reps;
+	DWORD	dwSize,dwSize2;
+	DWORD	*pbuf2;
+	HRESULT	hresult;
+#endif
+	
+	snd_vol = (int)(volume.value*256);
+
+	snd_p = paintbuffer.intbuf;
+	lpaintedtime = paintedtime;
+
+#ifdef _WIN32
+	if (pDSBuf)
+	{
+		reps = 0;
+
+		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
+									   &pbuf2, &dwSize2, 0)) != DS_OK)
+		{
+			if (hresult != DSERR_BUFFERLOST)
+			{
+				Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
+				S_Shutdown ();
+				S_Startup ();
+				return;
+			}
+
+			if (++reps > 10000)
+			{
+				Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
+				S_Shutdown ();
+				S_Startup ();
+				return;
+			}
+		}
+	}
+	else
+#endif
+	{
+		pbuf = (DWORD *)shm->buffer;
+	}
+
+	while (lpaintedtime < endtime)
+	{
+	// handle recirculating buffer issues
+		lpos = lpaintedtime & ((shm->samples>>1)-1);
+
+		snd_out = (short *) pbuf + (lpos<<1);
+
+		snd_linear_count = (shm->samples>>1) - lpos;
+		if (lpaintedtime + snd_linear_count > endtime)
+			snd_linear_count = endtime - lpaintedtime;
+
+		snd_linear_count <<= 1;
+
+	// write a linear blast of samples
+		Snd_WriteLinearBlastStereo16 ();
+
+		snd_p += snd_linear_count;
+		lpaintedtime += (snd_linear_count>>1);
+	}
+
+#ifdef _WIN32
+	if (pDSBuf)
+		pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
+#endif
+}
+
+void S_TransferPaintBuffer(int endtime)
+{
+	int 	out_idx;
+	int 	count;
+	int 	out_mask;
+	int 	*p;
+	int 	step;
+	int		val;
+	int		snd_vol;
+	DWORD	*pbuf;
+#ifdef _WIN32
+	int		reps;
+	DWORD	dwSize,dwSize2;
+	DWORD	*pbuf2;
+	HRESULT	hresult;
+#endif
+
+	if (shm->samplebits == 16 && shm->channels == 2)
+	{
+		S_TransferStereo16 (endtime);
+		return;
+	}
+	
+	p = paintbuffer.intbuf;
+	count = (endtime - paintedtime) * shm->channels;
+	out_mask = shm->samples - 1; 
+	out_idx = paintedtime * shm->channels & out_mask;
+	step = 3 - shm->channels;
+	snd_vol = (int)(volume.value*256);
+
+#ifdef _WIN32
+	if (pDSBuf)
+	{
+		reps = 0;
+
+		while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
+									   &pbuf2,&dwSize2, 0)) != DS_OK)
+		{
+			if (hresult != DSERR_BUFFERLOST)
+			{
+				Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
+				S_Shutdown ();
+				S_Startup ();
+				return;
+			}
+
+			if (++reps > 10000)
+			{
+				Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
+				S_Shutdown ();
+				S_Startup ();
+				return;
+			}
+		}
+	}
+	else
+#endif
+	{
+		pbuf = (DWORD *)shm->buffer;
+	}
+
+	if (shm->samplebits == 16)
+	{
+		short *out = (short *) pbuf;
+		while (count--)
+		{
+			val = (*p * snd_vol) >> 8;
+			p+= step;
+			if (val > 0x7fff)
+				val = 0x7fff;
+			else if (val < (short)0x8000)
+				val = (short)0x8000;
+			out[out_idx] = val;
+			out_idx = (out_idx + 1) & out_mask;
+		}
+	}
+	else if (shm->samplebits == 8)
+	{
+		unsigned char *out = (unsigned char *) pbuf;
+		while (count--)
+		{
+			val = (*p * snd_vol) >> 8;
+			p+= step;
+			if (val > 0x7fff)
+				val = 0x7fff;
+			else if (val < (short)0x8000)
+				val = (short)0x8000;
+			out[out_idx] = (val>>8) + 128;
+			out_idx = (out_idx + 1) & out_mask;
+		}
+	}
+
+#ifdef _WIN32
+	if (pDSBuf) {
+		DWORD dwNewpos, dwWrite;
+		int il = paintedtime;
+		int ir = endtime - paintedtime;
+		
+		ir += il;
+
+		pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
+
+		pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
+
+//		if ((dwNewpos >= il) && (dwNewpos <= ir))
+//			Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
+	}
+#endif
+}
+
+
+/*
+===============================================================================
+
+CHANNEL MIXING
+
+===============================================================================
+*/
+
+void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
+void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
+
+void S_PaintChannels(int endtime)
+{
+	int 	i;
+	int 	end;
+	channel_t *ch;
+	sfxcache_t	*sc;
+	int		ltime, count;
+
+	while (paintedtime < endtime)
+	{
+	// if paintbuffer is smaller than DMA buffer
+		end = endtime;
+		if (endtime - paintedtime > PAINTBUFFER_SIZE)
+			end = paintedtime + PAINTBUFFER_SIZE;
+
+	// clear the paint buffer
+		Q_memset(paintbuffer.paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
+
+	// paint in the channels.
+		ch = channels;
+		for (i=0; i<total_channels ; i++, ch++)
+		{
+			if (!ch->sfx)
+				continue;
+			if (!ch->leftvol && !ch->rightvol)
+				continue;
+			sc = S_LoadSound (ch->sfx);
+			if (!sc)
+				continue;
+
+			ltime = paintedtime;
+
+			while (ltime < end)
+			{	// paint up to end
+				if (ch->end < end)
+					count = ch->end - ltime;
+				else
+					count = end - ltime;
+
+				if (count > 0)
+				{	
+					if (sc->width == 1)
+						SND_PaintChannelFrom8(ch, sc, count);
+					else
+						SND_PaintChannelFrom16(ch, sc, count);
+	
+					ltime += count;
+				}
+
+			// if at end of loop, restart
+				if (ltime >= ch->end)
+				{
+					if (sc->loopstart >= 0)
+					{
+						ch->pos = sc->loopstart;
+						ch->end = ltime + sc->length - ch->pos;
+					}
+					else				
+					{	// channel just stopped
+						ch->sfx = NULL;
+						break;
+					}
+				}
+			}
+															  
+		}
+
+	// transfer out according to DMA format
+		S_TransferPaintBuffer(end);
+		paintedtime = end;
+	}
+}
+
+void SND_InitScaletable (void)
+{
+	int		i, j;
+	
+	for (i=0 ; i<32 ; i++)
+		for (j=0 ; j<256 ; j++)
+			snd_scaletable[i][j] = ((signed char)j) * i * 8;
+}
+
+
+#if	!id386
+
+void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
+{
+	int 	data;
+	int		*lscale, *rscale;
+	unsigned char *sfx;
+	int		i;
+
+	if (ch->leftvol > 255)
+		ch->leftvol = 255;
+	if (ch->rightvol > 255)
+		ch->rightvol = 255;
+		
+	lscale = snd_scaletable[ch->leftvol >> 3];
+	rscale = snd_scaletable[ch->rightvol >> 3];
+	sfx = sc->data.uc + ch->pos;
+
+	for (i=0 ; i<count ; i++)
+	{
+		data = sfx[i];
+		paintbuffer.paintbuffer[i].left += lscale[data];
+		paintbuffer.paintbuffer[i].right += rscale[data];
+	}
+	
+	ch->pos += count;
+}
+
+#endif	// !id386
+
+
+void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
+{
+	int data;
+	int left, right;
+	int leftvol, rightvol;
+	signed short *sfx;
+	int	i;
+
+	leftvol = ch->leftvol;
+	rightvol = ch->rightvol;
+	sfx = sc->data.ss + ch->pos;
+
+	for (i=0 ; i<count ; i++)
+	{
+		data = sfx[i];
+		left = (data * leftvol) >> 8;
+		right = (data * rightvol) >> 8;
+		paintbuffer.paintbuffer[i].left += left;
+		paintbuffer.paintbuffer[i].right += right;
+	}
+
+	ch->pos += count;
+}
+
diff --git a/quake/src/WinQuake/snd_next.c b/quake/src/WinQuake/snd_next.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/snd_next.c
rename to quake/src/WinQuake/snd_next.cpp
diff --git a/quake/src/WinQuake/snd_null.c b/quake/src/WinQuake/snd_null.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/snd_null.c
rename to quake/src/WinQuake/snd_null.cpp
diff --git a/quake/src/WinQuake/snd_sun.c b/quake/src/WinQuake/snd_sun.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/snd_sun.c
rename to quake/src/WinQuake/snd_sun.cpp
diff --git a/quake/src/WinQuake/snd_win.c b/quake/src/WinQuake/snd_win.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/snd_win.c
rename to quake/src/WinQuake/snd_win.cpp
diff --git a/quake/src/WinQuake/sound.h b/quake/src/WinQuake/sound.h
index 6410af2..349b859 100644
--- a/quake/src/WinQuake/sound.h
+++ b/quake/src/WinQuake/sound.h
@@ -1,177 +1,183 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// sound.h -- client sound i/o functions

-

-#ifndef __SOUND__

-#define __SOUND__

-

-#define DEFAULT_SOUND_PACKET_VOLUME 255

-#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0

-

-// !!! if this is changed, it much be changed in asm_i386.h too !!!

-typedef struct

-{

-	int left;

-	int right;

-} portable_samplepair_t;

-

-typedef struct sfx_s

-{

-	char 	name[MAX_QPATH];

-	cache_user_t	cache;

-} sfx_t;

-

-// !!! if this is changed, it much be changed in asm_i386.h too !!!

-typedef struct

-{

-	int 	length;

-	int 	loopstart;

-	int 	speed;

-	int 	width;

-	int 	stereo;

-	byte	data[1];		// variable sized

-} sfxcache_t;

-

-typedef struct

-{

-	qboolean		gamealive;

-	qboolean		soundalive;

-	qboolean		splitbuffer;

-	int				channels;

-	int				samples;				// mono samples in buffer

-	int				submission_chunk;		// don't mix less than this #

-	int				samplepos;				// in mono samples

-	int				samplebits;

-	int				speed;

-	unsigned char	*buffer;

-} dma_t;

-

-// !!! if this is changed, it much be changed in asm_i386.h too !!!

-typedef struct

-{

-	sfx_t	*sfx;			// sfx number

-	int		leftvol;		// 0-255 volume

-	int		rightvol;		// 0-255 volume

-	int		end;			// end time in global paintsamples

-	int 	pos;			// sample position in sfx

-	int		looping;		// where to loop, -1 = no looping

-	int		entnum;			// to allow overriding a specific sound

-	int		entchannel;		//

-	vec3_t	origin;			// origin of sound effect

-	vec_t	dist_mult;		// distance multiplier (attenuation/clipK)

-	int		master_vol;		// 0-255 master volume

-} channel_t;

-

-typedef struct

-{

-	int		rate;

-	int		width;

-	int		channels;

-	int		loopstart;

-	int		samples;

-	int		dataofs;		// chunk starts this many bytes from file start

-} wavinfo_t;

-

-void S_Init (void);

-void S_Startup (void);

-void S_Shutdown (void);

-void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol,  float attenuation);

-void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);

-void S_StopSound (int entnum, int entchannel);

-void S_StopAllSounds(qboolean clear);

-void S_ClearBuffer (void);

-void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);

-void S_ExtraUpdate (void);

-

-sfx_t *S_PrecacheSound (char *sample);

-void S_TouchSound (char *sample);

-void S_ClearPrecache (void);

-void S_BeginPrecaching (void);

-void S_EndPrecaching (void);

-void S_PaintChannels(int endtime);

-void S_InitPaintChannels (void);

-

-// picks a channel based on priorities, empty slots, number of channels

-channel_t *SND_PickChannel(int entnum, int entchannel);

-

-// spatializes a channel

-void SND_Spatialize(channel_t *ch);

-

-// initializes cycling through a DMA buffer and returns information on it

-qboolean SNDDMA_Init(void);

-

-// gets the current DMA position

-int SNDDMA_GetDMAPos(void);

-

-// shutdown the DMA xfer.

-void SNDDMA_Shutdown(void);

-

-// ====================================================================

-// User-setable variables

-// ====================================================================

-

-#define	MAX_CHANNELS			128

-#define	MAX_DYNAMIC_CHANNELS	8

-

-

-extern	channel_t   channels[MAX_CHANNELS];

-// 0 to MAX_DYNAMIC_CHANNELS-1	= normal entity sounds

-// MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc

-// MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds

-

-extern	int			total_channels;

-

-//

-// Fake dma is a synchronous faking of the DMA progress used for

-// isolating performance in the renderer.  The fakedma_updates is

-// number of times S_Update() is called per second.

-//

-

-extern qboolean 		fakedma;

-extern int 			fakedma_updates;

-extern int		paintedtime;

-extern vec3_t listener_origin;

-extern vec3_t listener_forward;

-extern vec3_t listener_right;

-extern vec3_t listener_up;

-extern volatile dma_t *shm;

-extern volatile dma_t sn;

-extern vec_t sound_nominal_clip_dist;

-

-extern	cvar_t loadas8bit;

-extern	cvar_t bgmvolume;

-extern	cvar_t volume;

-

-extern qboolean	snd_initialized;

-

-extern int		snd_blocked;

-

-void S_LocalSound (char *s);

-sfxcache_t *S_LoadSound (sfx_t *s);

-

-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);

-

-void SND_InitScaletable (void);

-void SNDDMA_Submit(void);

-

-void S_AmbientOff (void);

-void S_AmbientOn (void);

-

-#endif

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// sound.h -- client sound i/o functions
+
+#ifndef __SOUND__
+#define __SOUND__
+
+#define DEFAULT_SOUND_PACKET_VOLUME 255
+#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
+
+// !!! if this is changed, it much be changed in asm_i386.h too !!!
+typedef struct
+{
+	int left;
+	int right;
+} portable_samplepair_t;
+
+typedef struct sfx_s
+{
+	char 	name[MAX_QPATH];
+	cache_user_t	cache;
+} sfx_t;
+
+// !!! if this is changed, it much be changed in asm_i386.h too !!!
+typedef struct
+{
+	int 	length;
+	int 	loopstart;
+	int 	speed;
+	int 	width;
+	int 	stereo;
+	union {
+	    byte	b[1];
+	    unsigned char uc[1];
+	    signed char sc[1];
+	    short s[1];
+	    signed short ss[1];
+	} data; // variable sized
+} sfxcache_t;
+
+typedef struct
+{
+	qboolean		gamealive;
+	qboolean		soundalive;
+	qboolean		splitbuffer;
+	int				channels;
+	int				samples;				// mono samples in buffer
+	int				submission_chunk;		// don't mix less than this #
+	int				samplepos;				// in mono samples
+	int				samplebits;
+	int				speed;
+	unsigned char	*buffer;
+} dma_t;
+
+// !!! if this is changed, it much be changed in asm_i386.h too !!!
+typedef struct
+{
+	sfx_t	*sfx;			// sfx number
+	int		leftvol;		// 0-255 volume
+	int		rightvol;		// 0-255 volume
+	int		end;			// end time in global paintsamples
+	int 	pos;			// sample position in sfx
+	int		looping;		// where to loop, -1 = no looping
+	int		entnum;			// to allow overriding a specific sound
+	int		entchannel;		//
+	vec3_t	origin;			// origin of sound effect
+	vec_t	dist_mult;		// distance multiplier (attenuation/clipK)
+	int		master_vol;		// 0-255 master volume
+} channel_t;
+
+typedef struct
+{
+	int		rate;
+	int		width;
+	int		channels;
+	int		loopstart;
+	int		samples;
+	int		dataofs;		// chunk starts this many bytes from file start
+} wavinfo_t;
+
+void S_Init (void);
+void S_Startup (void);
+void S_Shutdown (void);
+void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol,  float attenuation);
+void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);
+void S_StopSound (int entnum, int entchannel);
+void S_StopAllSounds(qboolean clear);
+void S_ClearBuffer (void);
+void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
+void S_ExtraUpdate (void);
+
+sfx_t *S_PrecacheSound (const char *sample);
+void S_TouchSound (const char *sample);
+void S_ClearPrecache (void);
+void S_BeginPrecaching (void);
+void S_EndPrecaching (void);
+void S_PaintChannels(int endtime);
+void S_InitPaintChannels (void);
+
+// picks a channel based on priorities, empty slots, number of channels
+channel_t *SND_PickChannel(int entnum, int entchannel);
+
+// spatializes a channel
+void SND_Spatialize(channel_t *ch);
+
+// initializes cycling through a DMA buffer and returns information on it
+qboolean SNDDMA_Init(void);
+
+// gets the current DMA position
+int SNDDMA_GetDMAPos(void);
+
+// shutdown the DMA xfer.
+void SNDDMA_Shutdown(void);
+
+// ====================================================================
+// User-setable variables
+// ====================================================================
+
+#define	MAX_CHANNELS			128
+#define	MAX_DYNAMIC_CHANNELS	8
+
+
+extern	channel_t   channels[MAX_CHANNELS];
+// 0 to MAX_DYNAMIC_CHANNELS-1	= normal entity sounds
+// MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc
+// MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds
+
+extern	int			total_channels;
+
+//
+// Fake dma is a synchronous faking of the DMA progress used for
+// isolating performance in the renderer.  The fakedma_updates is
+// number of times S_Update() is called per second.
+//
+
+extern qboolean 		fakedma;
+extern int 			fakedma_updates;
+extern int		paintedtime;
+extern vec3_t listener_origin;
+extern vec3_t listener_forward;
+extern vec3_t listener_right;
+extern vec3_t listener_up;
+extern volatile dma_t *shm;
+extern volatile dma_t sn;
+extern vec_t sound_nominal_clip_dist;
+
+extern	cvar_t loadas8bit;
+extern	cvar_t bgmvolume;
+extern	cvar_t volume;
+
+extern qboolean	snd_initialized;
+
+extern int		snd_blocked;
+
+void S_LocalSound (const char *s);
+sfxcache_t *S_LoadSound (sfx_t *s);
+
+wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
+
+void SND_InitScaletable (void);
+void SNDDMA_Submit(void);
+
+void S_AmbientOff (void);
+void S_AmbientOn (void);
+
+#endif
diff --git a/quake/src/WinQuake/spritegn.h b/quake/src/WinQuake/spritegn.h
index 337c1d6..d2061ec 100644
--- a/quake/src/WinQuake/spritegn.h
+++ b/quake/src/WinQuake/spritegn.h
@@ -63,7 +63,7 @@
 // must match definition in modelgen.h

 #ifndef SYNCTYPE_T

 #define SYNCTYPE_T

-typedef enum {ST_SYNC=0, ST_RAND } synctype_t;

+typedef enum {ST_SYNC=0, ST_RAND, synctype_t_max = 1<<30 } synctype_t;

 #endif

 

 // TODO: shorten these?

@@ -99,7 +99,7 @@
 	float	interval;

 } dspriteinterval_t;

 

-typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t;

+typedef enum { SPR_SINGLE=0, SPR_GROUP, spriteframetype_t_max = 1 << 30 } spriteframetype_t;

 

 typedef struct {

 	spriteframetype_t	type;

diff --git a/quake/src/WinQuake/sv_main.c b/quake/src/WinQuake/sv_main.cpp
old mode 100644
new mode 100755
similarity index 84%
rename from quake/src/WinQuake/sv_main.c
rename to quake/src/WinQuake/sv_main.cpp
index ae38b18..3845d30
--- a/quake/src/WinQuake/sv_main.c
+++ b/quake/src/WinQuake/sv_main.cpp
@@ -1,1200 +1,1200 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// sv_main.c -- server main program

-

-#include "quakedef.h"

-

-server_t		sv;

-server_static_t	svs;

-

-char	localmodels[MAX_MODELS][5];			// inline model names for precache

-

-//============================================================================

-

-/*

-===============

-SV_Init

-===============

-*/

-void SV_Init (void)

-{

-	int		i;

-	extern	cvar_t	sv_maxvelocity;

-	extern	cvar_t	sv_gravity;

-	extern	cvar_t	sv_nostep;

-	extern	cvar_t	sv_friction;

-	extern	cvar_t	sv_edgefriction;

-	extern	cvar_t	sv_stopspeed;

-	extern	cvar_t	sv_maxspeed;

-	extern	cvar_t	sv_accelerate;

-	extern	cvar_t	sv_idealpitchscale;

-	extern	cvar_t	sv_aim;

-

-	Cvar_RegisterVariable (&sv_maxvelocity);

-	Cvar_RegisterVariable (&sv_gravity);

-	Cvar_RegisterVariable (&sv_friction);

-	Cvar_RegisterVariable (&sv_edgefriction);

-	Cvar_RegisterVariable (&sv_stopspeed);

-	Cvar_RegisterVariable (&sv_maxspeed);

-	Cvar_RegisterVariable (&sv_accelerate);

-	Cvar_RegisterVariable (&sv_idealpitchscale);

-	Cvar_RegisterVariable (&sv_aim);

-	Cvar_RegisterVariable (&sv_nostep);

-

-	for (i=0 ; i<MAX_MODELS ; i++)

-		sprintf (localmodels[i], "*%i", i);

-}

-

-/*

-=============================================================================

-

-EVENT MESSAGES

-

-=============================================================================

-*/

-

-/*  

-==================

-SV_StartParticle

-

-Make sure the event gets sent to all clients

-==================

-*/

-void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)

-{

-	int		i, v;

-

-	if (sv.datagram.cursize > MAX_DATAGRAM-16)

-		return;	

-	MSG_WriteByte (&sv.datagram, svc_particle);

-	MSG_WriteCoord (&sv.datagram, org[0]);

-	MSG_WriteCoord (&sv.datagram, org[1]);

-	MSG_WriteCoord (&sv.datagram, org[2]);

-	for (i=0 ; i<3 ; i++)

-	{

-		v = dir[i]*16;

-		if (v > 127)

-			v = 127;

-		else if (v < -128)

-			v = -128;

-		MSG_WriteChar (&sv.datagram, v);

-	}

-	MSG_WriteByte (&sv.datagram, count);

-	MSG_WriteByte (&sv.datagram, color);

-}           

-

-/*  

-==================

-SV_StartSound

-

-Each entity can have eight independant sound sources, like voice,

-weapon, feet, etc.

-

-Channel 0 is an auto-allocate channel, the others override anything

-allready running on that entity/channel pair.

-

-An attenuation of 0 will play full volume everywhere in the level.

-Larger attenuations will drop off.  (max 4 attenuation)

-

-==================

-*/  

-void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,

-    float attenuation)

-{       

-    int         sound_num;

-    int field_mask;

-    int			i;

-	int			ent;

-	

-	if (volume < 0 || volume > 255)

-		Sys_Error ("SV_StartSound: volume = %i", volume);

-

-	if (attenuation < 0 || attenuation > 4)

-		Sys_Error ("SV_StartSound: attenuation = %f", attenuation);

-

-	if (channel < 0 || channel > 7)

-		Sys_Error ("SV_StartSound: channel = %i", channel);

-

-	if (sv.datagram.cursize > MAX_DATAGRAM-16)

-		return;	

-

-// find precache number for sound

-    for (sound_num=1 ; sound_num<MAX_SOUNDS

-        && sv.sound_precache[sound_num] ; sound_num++)

-        if (!strcmp(sample, sv.sound_precache[sound_num]))

-            break;

-    

-    if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] )

-    {

-        Con_Printf ("SV_StartSound: %s not precacheed\n", sample);

-        return;

-    }

-    

-	ent = NUM_FOR_EDICT(entity);

-

-	channel = (ent<<3) | channel;

-

-	field_mask = 0;

-	if (volume != DEFAULT_SOUND_PACKET_VOLUME)

-		field_mask |= SND_VOLUME;

-	if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)

-		field_mask |= SND_ATTENUATION;

-

-// directed messages go only to the entity the are targeted on

-	MSG_WriteByte (&sv.datagram, svc_sound);

-	MSG_WriteByte (&sv.datagram, field_mask);

-	if (field_mask & SND_VOLUME)

-		MSG_WriteByte (&sv.datagram, volume);

-	if (field_mask & SND_ATTENUATION)

-		MSG_WriteByte (&sv.datagram, attenuation*64);

-	MSG_WriteShort (&sv.datagram, channel);

-	MSG_WriteByte (&sv.datagram, sound_num);

-	for (i=0 ; i<3 ; i++)

-		MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));

-}           

-

-/*

-==============================================================================

-

-CLIENT SPAWNING

-

-==============================================================================

-*/

-

-/*

-================

-SV_SendServerinfo

-

-Sends the first message from the server to a connected client.

-This will be sent on the initial connection and upon each server load.

-================

-*/

-void SV_SendServerinfo (client_t *client)

-{

-	char			**s;

-	char			message[2048];

-

-	MSG_WriteByte (&client->message, svc_print);

-	sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, VERSION, pr_crc);

-	MSG_WriteString (&client->message,message);

-

-	MSG_WriteByte (&client->message, svc_serverinfo);

-	MSG_WriteLong (&client->message, PROTOCOL_VERSION);

-	MSG_WriteByte (&client->message, svs.maxclients);

-

-	if (!coop.value && deathmatch.value)

-		MSG_WriteByte (&client->message, GAME_DEATHMATCH);

-	else

-		MSG_WriteByte (&client->message, GAME_COOP);

-

-	sprintf (message, pr_strings+sv.edicts->v.message);

-

-	MSG_WriteString (&client->message,message);

-

-	for (s = sv.model_precache+1 ; *s ; s++)

-		MSG_WriteString (&client->message, *s);

-	MSG_WriteByte (&client->message, 0);

-

-	for (s = sv.sound_precache+1 ; *s ; s++)

-		MSG_WriteString (&client->message, *s);

-	MSG_WriteByte (&client->message, 0);

-

-// send music

-	MSG_WriteByte (&client->message, svc_cdtrack);

-	MSG_WriteByte (&client->message, sv.edicts->v.sounds);

-	MSG_WriteByte (&client->message, sv.edicts->v.sounds);

-

-// set view	

-	MSG_WriteByte (&client->message, svc_setview);

-	MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict));

-

-	MSG_WriteByte (&client->message, svc_signonnum);

-	MSG_WriteByte (&client->message, 1);

-

-	client->sendsignon = true;

-	client->spawned = false;		// need prespawn, spawn, etc

-}

-

-/*

-================

-SV_ConnectClient

-

-Initializes a client_t for a new net connection.  This will only be called

-once for a player each game, not once for each level change.

-================

-*/

-void SV_ConnectClient (int clientnum)

-{

-	edict_t			*ent;

-	client_t		*client;

-	int				edictnum;

-	struct qsocket_s *netconnection;

-	int				i;

-	float			spawn_parms[NUM_SPAWN_PARMS];

-

-	client = svs.clients + clientnum;

-

-	Con_DPrintf ("Client %s connected\n", client->netconnection->address);

-

-	edictnum = clientnum+1;

-

-	ent = EDICT_NUM(edictnum);

-	

-// set up the client_t

-	netconnection = client->netconnection;

-	

-	if (sv.loadgame)

-		memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));

-	memset (client, 0, sizeof(*client));

-	client->netconnection = netconnection;

-

-	strcpy (client->name, "unconnected");

-	client->active = true;

-	client->spawned = false;

-	client->edict = ent;

-	client->message.data = client->msgbuf;

-	client->message.maxsize = sizeof(client->msgbuf);

-	client->message.allowoverflow = true;		// we can catch it

-

-#ifdef IDGODS

-	client->privileged = IsID(&client->netconnection->addr);

-#else	

-	client->privileged = false;				

-#endif

-

-	if (sv.loadgame)

-		memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));

-	else

-	{

-	// call the progs to get default spawn parms for the new client

-		PR_ExecuteProgram (pr_global_struct->SetNewParms);

-		for (i=0 ; i<NUM_SPAWN_PARMS ; i++)

-			client->spawn_parms[i] = (&pr_global_struct->parm1)[i];

-	}

-

-	SV_SendServerinfo (client);

-}

-

-

-/*

-===================

-SV_CheckForNewClients

-

-===================

-*/

-void SV_CheckForNewClients (void)

-{

-	struct qsocket_s	*ret;

-	int				i;

-		

-//

-// check for new connections

-//

-	while (1)

-	{

-		ret = NET_CheckNewConnections ();

-		if (!ret)

-			break;

-

-	// 

-	// init a new client structure

-	//	

-		for (i=0 ; i<svs.maxclients ; i++)

-			if (!svs.clients[i].active)

-				break;

-		if (i == svs.maxclients)

-			Sys_Error ("Host_CheckForNewClients: no free clients");

-		

-		svs.clients[i].netconnection = ret;

-		SV_ConnectClient (i);	

-	

-		net_activeconnections++;

-	}

-}

-

-

-

-/*

-===============================================================================

-

-FRAME UPDATES

-

-===============================================================================

-*/

-

-/*

-==================

-SV_ClearDatagram

-

-==================

-*/

-void SV_ClearDatagram (void)

-{

-	SZ_Clear (&sv.datagram);

-}

-

-/*

-=============================================================================

-

-The PVS must include a small area around the client to allow head bobbing

-or other small motion on the client side.  Otherwise, a bob might cause an

-entity that should be visible to not show up, especially when the bob

-crosses a waterline.

-

-=============================================================================

-*/

-

-int		fatbytes;

-byte	fatpvs[MAX_MAP_LEAFS/8];

-

-void SV_AddToFatPVS (vec3_t org, mnode_t *node)

-{

-	int		i;

-	byte	*pvs;

-	mplane_t	*plane;

-	float	d;

-

-	while (1)

-	{

-	// if this is a leaf, accumulate the pvs bits

-		if (node->contents < 0)

-		{

-			if (node->contents != CONTENTS_SOLID)

-			{

-				pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel);

-				for (i=0 ; i<fatbytes ; i++)

-					fatpvs[i] |= pvs[i];

-			}

-			return;

-		}

-	

-		plane = node->plane;

-		d = DotProduct (org, plane->normal) - plane->dist;

-		if (d > 8)

-			node = node->children[0];

-		else if (d < -8)

-			node = node->children[1];

-		else

-		{	// go down both

-			SV_AddToFatPVS (org, node->children[0]);

-			node = node->children[1];

-		}

-	}

-}

-

-/*

-=============

-SV_FatPVS

-

-Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the

-given point.

-=============

-*/

-byte *SV_FatPVS (vec3_t org)

-{

-	fatbytes = (sv.worldmodel->numleafs+31)>>3;

-	Q_memset (fatpvs, 0, fatbytes);

-	SV_AddToFatPVS (org, sv.worldmodel->nodes);

-	return fatpvs;

-}

-

-//=============================================================================

-

-

-/*

-=============

-SV_WriteEntitiesToClient

-

-=============

-*/

-void SV_WriteEntitiesToClient (edict_t	*clent, sizebuf_t *msg)

-{

-	int		e, i;

-	int		bits;

-	byte	*pvs;

-	vec3_t	org;

-	float	miss;

-	edict_t	*ent;

-

-// find the client's PVS

-	VectorAdd (clent->v.origin, clent->v.view_ofs, org);

-	pvs = SV_FatPVS (org);

-

-// send over all entities (excpet the client) that touch the pvs

-	ent = NEXT_EDICT(sv.edicts);

-	for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))

-	{

-#ifdef QUAKE2

-		// don't send if flagged for NODRAW and there are no lighting effects

-		if (ent->v.effects == EF_NODRAW)

-			continue;

-#endif

-

-// ignore if not touching a PV leaf

-		if (ent != clent)	// clent is ALLWAYS sent

-		{

-// ignore ents without visible models

-			if (!ent->v.modelindex || !pr_strings[ent->v.model])

-				continue;

-

-			for (i=0 ; i < ent->num_leafs ; i++)

-				if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))

-					break;

-				

-			if (i == ent->num_leafs)

-				continue;		// not visible

-		}

-

-		if (msg->maxsize - msg->cursize < 16)

-		{

-			Con_Printf ("packet overflow\n");

-			return;

-		}

-

-// send an update

-		bits = 0;

-		

-		for (i=0 ; i<3 ; i++)

-		{

-			miss = ent->v.origin[i] - ent->baseline.origin[i];

-			if ( miss < -0.1 || miss > 0.1 )

-				bits |= U_ORIGIN1<<i;

-		}

-

-		if ( ent->v.angles[0] != ent->baseline.angles[0] )

-			bits |= U_ANGLE1;

-			

-		if ( ent->v.angles[1] != ent->baseline.angles[1] )

-			bits |= U_ANGLE2;

-			

-		if ( ent->v.angles[2] != ent->baseline.angles[2] )

-			bits |= U_ANGLE3;

-			

-		if (ent->v.movetype == MOVETYPE_STEP)

-			bits |= U_NOLERP;	// don't mess up the step animation

-	

-		if (ent->baseline.colormap != ent->v.colormap)

-			bits |= U_COLORMAP;

-			

-		if (ent->baseline.skin != ent->v.skin)

-			bits |= U_SKIN;

-			

-		if (ent->baseline.frame != ent->v.frame)

-			bits |= U_FRAME;

-		

-		if (ent->baseline.effects != ent->v.effects)

-			bits |= U_EFFECTS;

-		

-		if (ent->baseline.modelindex != ent->v.modelindex)

-			bits |= U_MODEL;

-

-		if (e >= 256)

-			bits |= U_LONGENTITY;

-			

-		if (bits >= 256)

-			bits |= U_MOREBITS;

-

-	//

-	// write the message

-	//

-		MSG_WriteByte (msg,bits | U_SIGNAL);

-		

-		if (bits & U_MOREBITS)

-			MSG_WriteByte (msg, bits>>8);

-		if (bits & U_LONGENTITY)

-			MSG_WriteShort (msg,e);

-		else

-			MSG_WriteByte (msg,e);

-

-		if (bits & U_MODEL)

-			MSG_WriteByte (msg,	ent->v.modelindex);

-		if (bits & U_FRAME)

-			MSG_WriteByte (msg, ent->v.frame);

-		if (bits & U_COLORMAP)

-			MSG_WriteByte (msg, ent->v.colormap);

-		if (bits & U_SKIN)

-			MSG_WriteByte (msg, ent->v.skin);

-		if (bits & U_EFFECTS)

-			MSG_WriteByte (msg, ent->v.effects);

-		if (bits & U_ORIGIN1)

-			MSG_WriteCoord (msg, ent->v.origin[0]);		

-		if (bits & U_ANGLE1)

-			MSG_WriteAngle(msg, ent->v.angles[0]);

-		if (bits & U_ORIGIN2)

-			MSG_WriteCoord (msg, ent->v.origin[1]);

-		if (bits & U_ANGLE2)

-			MSG_WriteAngle(msg, ent->v.angles[1]);

-		if (bits & U_ORIGIN3)

-			MSG_WriteCoord (msg, ent->v.origin[2]);

-		if (bits & U_ANGLE3)

-			MSG_WriteAngle(msg, ent->v.angles[2]);

-	}

-}

-

-/*

-=============

-SV_CleanupEnts

-

-=============

-*/

-void SV_CleanupEnts (void)

-{

-	int		e;

-	edict_t	*ent;

-	

-	ent = NEXT_EDICT(sv.edicts);

-	for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))

-	{

-		ent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH;

-	}

-

-}

-

-/*

-==================

-SV_WriteClientdataToMessage

-

-==================

-*/

-void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)

-{

-	int		bits;

-	int		i;

-	edict_t	*other;

-	int		items;

-#ifndef QUAKE2

-	eval_t	*val;

-#endif

-

-//

-// send a damage message

-//

-	if (ent->v.dmg_take || ent->v.dmg_save)

-	{

-		other = PROG_TO_EDICT(ent->v.dmg_inflictor);

-		MSG_WriteByte (msg, svc_damage);

-		MSG_WriteByte (msg, ent->v.dmg_save);

-		MSG_WriteByte (msg, ent->v.dmg_take);

-		for (i=0 ; i<3 ; i++)

-			MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));

-	

-		ent->v.dmg_take = 0;

-		ent->v.dmg_save = 0;

-	}

-

-//

-// send the current viewpos offset from the view entity

-//

-	SV_SetIdealPitch ();		// how much to look up / down ideally

-

-// a fixangle might get lost in a dropped packet.  Oh well.

-	if ( ent->v.fixangle )

-	{

-		MSG_WriteByte (msg, svc_setangle);

-		for (i=0 ; i < 3 ; i++)

-			MSG_WriteAngle (msg, ent->v.angles[i] );

-		ent->v.fixangle = 0;

-	}

-

-	bits = 0;

-	

-	if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)

-		bits |= SU_VIEWHEIGHT;

-		

-	if (ent->v.idealpitch)

-		bits |= SU_IDEALPITCH;

-

-// stuff the sigil bits into the high bits of items for sbar, or else

-// mix in items2

-#ifdef QUAKE2

-	items = (int)ent->v.items | ((int)ent->v.items2 << 23);

-#else

-	val = GetEdictFieldValue(ent, "items2");

-

-	if (val)

-		items = (int)ent->v.items | ((int)val->_float << 23);

-	else

-		items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);

-#endif

-

-	bits |= SU_ITEMS;

-	

-	if ( (int)ent->v.flags & FL_ONGROUND)

-		bits |= SU_ONGROUND;

-	

-	if ( ent->v.waterlevel >= 2)

-		bits |= SU_INWATER;

-	

-	for (i=0 ; i<3 ; i++)

-	{

-		if (ent->v.punchangle[i])

-			bits |= (SU_PUNCH1<<i);

-		if (ent->v.velocity[i])

-			bits |= (SU_VELOCITY1<<i);

-	}

-	

-	if (ent->v.weaponframe)

-		bits |= SU_WEAPONFRAME;

-

-	if (ent->v.armorvalue)

-		bits |= SU_ARMOR;

-

-//	if (ent->v.weapon)

-		bits |= SU_WEAPON;

-

-// send the data

-

-	MSG_WriteByte (msg, svc_clientdata);

-	MSG_WriteShort (msg, bits);

-

-	if (bits & SU_VIEWHEIGHT)

-		MSG_WriteChar (msg, ent->v.view_ofs[2]);

-

-	if (bits & SU_IDEALPITCH)

-		MSG_WriteChar (msg, ent->v.idealpitch);

-

-	for (i=0 ; i<3 ; i++)

-	{

-		if (bits & (SU_PUNCH1<<i))

-			MSG_WriteChar (msg, ent->v.punchangle[i]);

-		if (bits & (SU_VELOCITY1<<i))

-			MSG_WriteChar (msg, ent->v.velocity[i]/16);

-	}

-

-// [always sent]	if (bits & SU_ITEMS)

-	MSG_WriteLong (msg, items);

-

-	if (bits & SU_WEAPONFRAME)

-		MSG_WriteByte (msg, ent->v.weaponframe);

-	if (bits & SU_ARMOR)

-		MSG_WriteByte (msg, ent->v.armorvalue);

-	if (bits & SU_WEAPON)

-		MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel));

-	

-	MSG_WriteShort (msg, ent->v.health);

-	MSG_WriteByte (msg, ent->v.currentammo);

-	MSG_WriteByte (msg, ent->v.ammo_shells);

-	MSG_WriteByte (msg, ent->v.ammo_nails);

-	MSG_WriteByte (msg, ent->v.ammo_rockets);

-	MSG_WriteByte (msg, ent->v.ammo_cells);

-

-	if (standard_quake)

-	{

-		MSG_WriteByte (msg, ent->v.weapon);

-	}

-	else

-	{

-		for(i=0;i<32;i++)

-		{

-			if ( ((int)ent->v.weapon) & (1<<i) )

-			{

-				MSG_WriteByte (msg, i);

-				break;

-			}

-		}

-	}

-}

-

-/*

-=======================

-SV_SendClientDatagram

-=======================

-*/

-qboolean SV_SendClientDatagram (client_t *client)

-{

-	byte		buf[MAX_DATAGRAM];

-	sizebuf_t	msg;

-	

-	msg.data = buf;

-	msg.maxsize = sizeof(buf);

-	msg.cursize = 0;

-

-	MSG_WriteByte (&msg, svc_time);

-	MSG_WriteFloat (&msg, sv.time);

-

-// add the client specific data to the datagram

-	SV_WriteClientdataToMessage (client->edict, &msg);

-

-	SV_WriteEntitiesToClient (client->edict, &msg);

-

-// copy the server datagram if there is space

-	if (msg.cursize + sv.datagram.cursize < msg.maxsize)

-		SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);

-

-// send the datagram

-	if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)

-	{

-		SV_DropClient (true);// if the message couldn't send, kick off

-		return false;

-	}

-	

-	return true;

-}

-

-/*

-=======================

-SV_UpdateToReliableMessages

-=======================

-*/

-void SV_UpdateToReliableMessages (void)

-{

-	int			i, j;

-	client_t *client;

-

-// check for changes to be sent over the reliable streams

-	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)

-	{

-		if (host_client->old_frags != host_client->edict->v.frags)

-		{

-			for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)

-			{

-				if (!client->active)

-					continue;

-				MSG_WriteByte (&client->message, svc_updatefrags);

-				MSG_WriteByte (&client->message, i);

-				MSG_WriteShort (&client->message, host_client->edict->v.frags);

-			}

-

-			host_client->old_frags = host_client->edict->v.frags;

-		}

-	}

-	

-	for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)

-	{

-		if (!client->active)

-			continue;

-		SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);

-	}

-

-	SZ_Clear (&sv.reliable_datagram);

-}

-

-

-/*

-=======================

-SV_SendNop

-

-Send a nop message without trashing or sending the accumulated client

-message buffer

-=======================

-*/

-void SV_SendNop (client_t *client)

-{

-	sizebuf_t	msg;

-	byte		buf[4];

-	

-	msg.data = buf;

-	msg.maxsize = sizeof(buf);

-	msg.cursize = 0;

-

-	MSG_WriteChar (&msg, svc_nop);

-

-	if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)

-		SV_DropClient (true);	// if the message couldn't send, kick off

-	client->last_message = realtime;

-}

-

-/*

-=======================

-SV_SendClientMessages

-=======================

-*/

-void SV_SendClientMessages (void)

-{

-	int			i;

-	

-// update frags, names, etc

-	SV_UpdateToReliableMessages ();

-

-// build individual updates

-	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)

-	{

-		if (!host_client->active)

-			continue;

-

-		if (host_client->spawned)

-		{

-			if (!SV_SendClientDatagram (host_client))

-				continue;

-		}

-		else

-		{

-		// the player isn't totally in the game yet

-		// send small keepalive messages if too much time has passed

-		// send a full message when the next signon stage has been requested

-		// some other message data (name changes, etc) may accumulate 

-		// between signon stages

-			if (!host_client->sendsignon)

-			{

-				if (realtime - host_client->last_message > 5)

-					SV_SendNop (host_client);

-				continue;	// don't send out non-signon messages

-			}

-		}

-

-		// check for an overflowed message.  Should only happen

-		// on a very fucked up connection that backs up a lot, then

-		// changes level

-		if (host_client->message.overflowed)

-		{

-			SV_DropClient (true);

-			host_client->message.overflowed = false;

-			continue;

-		}

-			

-		if (host_client->message.cursize || host_client->dropasap)

-		{

-			if (!NET_CanSendMessage (host_client->netconnection))

-			{

-//				I_Printf ("can't write\n");

-				continue;

-			}

-

-			if (host_client->dropasap)

-				SV_DropClient (false);	// went to another level

-			else

-			{

-				if (NET_SendMessage (host_client->netconnection

-				, &host_client->message) == -1)

-					SV_DropClient (true);	// if the message couldn't send, kick off

-				SZ_Clear (&host_client->message);

-				host_client->last_message = realtime;

-				host_client->sendsignon = false;

-			}

-		}

-	}

-	

-	

-// clear muzzle flashes

-	SV_CleanupEnts ();

-}

-

-

-/*

-==============================================================================

-

-SERVER SPAWNING

-

-==============================================================================

-*/

-

-/*

-================

-SV_ModelIndex

-

-================

-*/

-int SV_ModelIndex (char *name)

-{

-	int		i;

-	

-	if (!name || !name[0])

-		return 0;

-

-	for (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++)

-		if (!strcmp(sv.model_precache[i], name))

-			return i;

-	if (i==MAX_MODELS || !sv.model_precache[i])

-		Sys_Error ("SV_ModelIndex: model %s not precached", name);

-	return i;

-}

-

-/*

-================

-SV_CreateBaseline

-

-================

-*/

-void SV_CreateBaseline (void)

-{

-	int			i;

-	edict_t			*svent;

-	int				entnum;	

-		

-	for (entnum = 0; entnum < sv.num_edicts ; entnum++)

-	{

-	// get the current server version

-		svent = EDICT_NUM(entnum);

-		if (svent->free)

-			continue;

-		if (entnum > svs.maxclients && !svent->v.modelindex)

-			continue;

-

-	//

-	// create entity baseline

-	//

-		VectorCopy (svent->v.origin, svent->baseline.origin);

-		VectorCopy (svent->v.angles, svent->baseline.angles);

-		svent->baseline.frame = svent->v.frame;

-		svent->baseline.skin = svent->v.skin;

-		if (entnum > 0 && entnum <= svs.maxclients)

-		{

-			svent->baseline.colormap = entnum;

-			svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl");

-		}

-		else

-		{

-			svent->baseline.colormap = 0;

-			svent->baseline.modelindex =

-				SV_ModelIndex(pr_strings + svent->v.model);

-		}

-		

-	//

-	// add to the message

-	//

-		MSG_WriteByte (&sv.signon,svc_spawnbaseline);		

-		MSG_WriteShort (&sv.signon,entnum);

-

-		MSG_WriteByte (&sv.signon, svent->baseline.modelindex);

-		MSG_WriteByte (&sv.signon, svent->baseline.frame);

-		MSG_WriteByte (&sv.signon, svent->baseline.colormap);

-		MSG_WriteByte (&sv.signon, svent->baseline.skin);

-		for (i=0 ; i<3 ; i++)

-		{

-			MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]);

-			MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);

-		}

-	}

-}

-

-

-/*

-================

-SV_SendReconnect

-

-Tell all the clients that the server is changing levels

-================

-*/

-void SV_SendReconnect (void)

-{

-	char	data[128];

-	sizebuf_t	msg;

-

-	msg.data = data;

-	msg.cursize = 0;

-	msg.maxsize = sizeof(data);

-

-	MSG_WriteChar (&msg, svc_stufftext);

-	MSG_WriteString (&msg, "reconnect\n");

-	NET_SendToAll (&msg, 5);

-	

-	if (cls.state != ca_dedicated)

-#ifdef QUAKE2

-		Cbuf_InsertText ("reconnect\n");

-#else

-		Cmd_ExecuteString ("reconnect\n", src_command);

-#endif

-}

-

-

-/*

-================

-SV_SaveSpawnparms

-

-Grabs the current state of each client for saving across the

-transition to another level

-================

-*/

-void SV_SaveSpawnparms (void)

-{

-	int		i, j;

-

-	svs.serverflags = pr_global_struct->serverflags;

-

-	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)

-	{

-		if (!host_client->active)

-			continue;

-

-	// call the progs to get default spawn parms for the new client

-		pr_global_struct->self = EDICT_TO_PROG(host_client->edict);

-		PR_ExecuteProgram (pr_global_struct->SetChangeParms);

-		for (j=0 ; j<NUM_SPAWN_PARMS ; j++)

-			host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j];

-	}

-}

-

-

-/*

-================

-SV_SpawnServer

-

-This is called at the start of each level

-================

-*/

-extern float		scr_centertime_off;

-

-#ifdef QUAKE2

-void SV_SpawnServer (char *server, char *startspot)

-#else

-void SV_SpawnServer (char *server)

-#endif

-{

-	edict_t		*ent;

-	int			i;

-

-	// let's not have any servers with no name

-	if (hostname.string[0] == 0)

-		Cvar_Set ("hostname", "UNNAMED");

-	scr_centertime_off = 0;

-

-	Con_DPrintf ("SpawnServer: %s\n",server);

-	svs.changelevel_issued = false;		// now safe to issue another

-

-//

-// tell all connected clients that we are going to a new level

-//

-	if (sv.active)

-	{

-		SV_SendReconnect ();

-	}

-

-//

-// make cvars consistant

-//

-	if (coop.value)

-		Cvar_SetValue ("deathmatch", 0);

-	current_skill = (int)(skill.value + 0.5);

-	if (current_skill < 0)

-		current_skill = 0;

-	if (current_skill > 3)

-		current_skill = 3;

-

-	Cvar_SetValue ("skill", (float)current_skill);

-	

-//

-// set up the new server

-//

-	Host_ClearMemory ();

-

-	memset (&sv, 0, sizeof(sv));

-

-	strcpy (sv.name, server);

-#ifdef QUAKE2

-	if (startspot)

-		strcpy(sv.startspot, startspot);

-#endif

-

-// load progs to get entity field count

-	PR_LoadProgs ();

-

-// allocate server memory

-	sv.max_edicts = MAX_EDICTS;

-	

-	sv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts");

-

-	sv.datagram.maxsize = sizeof(sv.datagram_buf);

-	sv.datagram.cursize = 0;

-	sv.datagram.data = sv.datagram_buf;

-	

-	sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);

-	sv.reliable_datagram.cursize = 0;

-	sv.reliable_datagram.data = sv.reliable_datagram_buf;

-	

-	sv.signon.maxsize = sizeof(sv.signon_buf);

-	sv.signon.cursize = 0;

-	sv.signon.data = sv.signon_buf;

-	

-// leave slots at start for clients only

-	sv.num_edicts = svs.maxclients+1;

-	for (i=0 ; i<svs.maxclients ; i++)

-	{

-		ent = EDICT_NUM(i+1);

-		svs.clients[i].edict = ent;

-	}

-	

-	sv.state = ss_loading;

-	sv.paused = false;

-

-	sv.time = 1.0;

-	

-	strcpy (sv.name, server);

-	sprintf (sv.modelname,"maps/%s.bsp", server);

-	sv.worldmodel = Mod_ForName (sv.modelname, false);

-	if (!sv.worldmodel)

-	{

-		Con_Printf ("Couldn't spawn server %s\n", sv.modelname);

-		sv.active = false;

-		return;

-	}

-	sv.models[1] = sv.worldmodel;

-	

-//

-// clear world interaction links

-//

-	SV_ClearWorld ();

-	

-	sv.sound_precache[0] = pr_strings;

-

-	sv.model_precache[0] = pr_strings;

-	sv.model_precache[1] = sv.modelname;

-	for (i=1 ; i<sv.worldmodel->numsubmodels ; i++)

-	{

-		sv.model_precache[1+i] = localmodels[i];

-		sv.models[i+1] = Mod_ForName (localmodels[i], false);

-	}

-

-//

-// load the rest of the entities

-//	

-	ent = EDICT_NUM(0);

-	memset (&ent->v, 0, progs->entityfields * 4);

-	ent->free = false;

-	ent->v.model = sv.worldmodel->name - pr_strings;

-	ent->v.modelindex = 1;		// world model

-	ent->v.solid = SOLID_BSP;

-	ent->v.movetype = MOVETYPE_PUSH;

-

-	if (coop.value)

-		pr_global_struct->coop = coop.value;

-	else

-		pr_global_struct->deathmatch = deathmatch.value;

-

-	pr_global_struct->mapname = sv.name - pr_strings;

-#ifdef QUAKE2

-	pr_global_struct->startspot = sv.startspot - pr_strings;

-#endif

-

-// serverflags are for cross level information (sigils)

-	pr_global_struct->serverflags = svs.serverflags;

-	

-	ED_LoadFromFile (sv.worldmodel->entities);

-

-	sv.active = true;

-

-// all setup is completed, any further precache statements are errors

-	sv.state = ss_active;

-	

-// run two frames to allow everything to settle

-	host_frametime = 0.1;

-	SV_Physics ();

-	SV_Physics ();

-

-// create a baseline for more efficient communications

-	SV_CreateBaseline ();

-

-// send serverinfo to all connected clients

-	for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)

-		if (host_client->active)

-			SV_SendServerinfo (host_client);

-	

-	Con_DPrintf ("Server spawned.\n");

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// sv_main.c -- server main program
+
+#include "quakedef.h"
+
+server_t		sv;
+server_static_t	svs;
+
+char	localmodels[MAX_MODELS][5];			// inline model names for precache
+
+//============================================================================
+
+/*
+===============
+SV_Init
+===============
+*/
+void SV_Init (void)
+{
+	int		i;
+	extern	cvar_t	sv_maxvelocity;
+	extern	cvar_t	sv_gravity;
+	extern	cvar_t	sv_nostep;
+	extern	cvar_t	sv_friction;
+	extern	cvar_t	sv_edgefriction;
+	extern	cvar_t	sv_stopspeed;
+	extern	cvar_t	sv_maxspeed;
+	extern	cvar_t	sv_accelerate;
+	extern	cvar_t	sv_idealpitchscale;
+	extern	cvar_t	sv_aim;
+
+	Cvar_RegisterVariable (&sv_maxvelocity);
+	Cvar_RegisterVariable (&sv_gravity);
+	Cvar_RegisterVariable (&sv_friction);
+	Cvar_RegisterVariable (&sv_edgefriction);
+	Cvar_RegisterVariable (&sv_stopspeed);
+	Cvar_RegisterVariable (&sv_maxspeed);
+	Cvar_RegisterVariable (&sv_accelerate);
+	Cvar_RegisterVariable (&sv_idealpitchscale);
+	Cvar_RegisterVariable (&sv_aim);
+	Cvar_RegisterVariable (&sv_nostep);
+
+	for (i=0 ; i<MAX_MODELS ; i++)
+		sprintf (localmodels[i], "*%i", i);
+}
+
+/*
+=============================================================================
+
+EVENT MESSAGES
+
+=============================================================================
+*/
+
+/*  
+==================
+SV_StartParticle
+
+Make sure the event gets sent to all clients
+==================
+*/
+void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
+{
+	int		i, v;
+
+	if (sv.datagram.cursize > MAX_DATAGRAM-16)
+		return;	
+	MSG_WriteByte (&sv.datagram, svc_particle);
+	MSG_WriteCoord (&sv.datagram, org[0]);
+	MSG_WriteCoord (&sv.datagram, org[1]);
+	MSG_WriteCoord (&sv.datagram, org[2]);
+	for (i=0 ; i<3 ; i++)
+	{
+		v = (int)(dir[i]*16);
+		if (v > 127)
+			v = 127;
+		else if (v < -128)
+			v = -128;
+		MSG_WriteChar (&sv.datagram, v);
+	}
+	MSG_WriteByte (&sv.datagram, count);
+	MSG_WriteByte (&sv.datagram, color);
+}           
+
+/*  
+==================
+SV_StartSound
+
+Each entity can have eight independant sound sources, like voice,
+weapon, feet, etc.
+
+Channel 0 is an auto-allocate channel, the others override anything
+allready running on that entity/channel pair.
+
+An attenuation of 0 will play full volume everywhere in the level.
+Larger attenuations will drop off.  (max 4 attenuation)
+
+==================
+*/  
+void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
+    float attenuation)
+{       
+    int         sound_num;
+    int field_mask;
+    int			i;
+	int			ent;
+	
+	if (volume < 0 || volume > 255)
+		Sys_Error ("SV_StartSound: volume = %i", volume);
+
+	if (attenuation < 0 || attenuation > 4)
+		Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
+
+	if (channel < 0 || channel > 7)
+		Sys_Error ("SV_StartSound: channel = %i", channel);
+
+	if (sv.datagram.cursize > MAX_DATAGRAM-16)
+		return;	
+
+// find precache number for sound
+    for (sound_num=1 ; sound_num<MAX_SOUNDS
+        && sv.sound_precache[sound_num] ; sound_num++)
+        if (!strcmp(sample, sv.sound_precache[sound_num]))
+            break;
+    
+    if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] )
+    {
+        Con_Printf ("SV_StartSound: %s not precacheed\n", sample);
+        return;
+    }
+    
+	ent = NUM_FOR_EDICT(entity);
+
+	channel = (ent<<3) | channel;
+
+	field_mask = 0;
+	if (volume != DEFAULT_SOUND_PACKET_VOLUME)
+		field_mask |= SND_VOLUME;
+	if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
+		field_mask |= SND_ATTENUATION;
+
+// directed messages go only to the entity the are targeted on
+	MSG_WriteByte (&sv.datagram, svc_sound);
+	MSG_WriteByte (&sv.datagram, field_mask);
+	if (field_mask & SND_VOLUME)
+		MSG_WriteByte (&sv.datagram, volume);
+	if (field_mask & SND_ATTENUATION)
+		MSG_WriteByte (&sv.datagram, (int) (attenuation*64));
+	MSG_WriteShort (&sv.datagram, channel);
+	MSG_WriteByte (&sv.datagram, sound_num);
+	for (i=0 ; i<3 ; i++)
+		MSG_WriteCoord (&sv.datagram, entity->u.v.origin[i]+0.5*(entity->u.v.mins[i]+entity->u.v.maxs[i]));
+}           
+
+/*
+==============================================================================
+
+CLIENT SPAWNING
+
+==============================================================================
+*/
+
+/*
+================
+SV_SendServerinfo
+
+Sends the first message from the server to a connected client.
+This will be sent on the initial connection and upon each server load.
+================
+*/
+void SV_SendServerinfo (client_t *client)
+{
+	char			**s;
+	char			message[2048];
+
+	MSG_WriteByte (&client->message, svc_print);
+	sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, VERSION, pr_crc);
+	MSG_WriteString (&client->message,message);
+
+	MSG_WriteByte (&client->message, svc_serverinfo);
+	MSG_WriteLong (&client->message, PROTOCOL_VERSION);
+	MSG_WriteByte (&client->message, svs.maxclients);
+
+	if (!coop.value && deathmatch.value)
+		MSG_WriteByte (&client->message, GAME_DEATHMATCH);
+	else
+		MSG_WriteByte (&client->message, GAME_COOP);
+
+	sprintf (message, pr_strings+sv.edicts->u.v.message);
+
+	MSG_WriteString (&client->message,message);
+
+	for (s = sv.model_precache+1 ; *s ; s++)
+		MSG_WriteString (&client->message, *s);
+	MSG_WriteByte (&client->message, 0);
+
+	for (s = sv.sound_precache+1 ; *s ; s++)
+		MSG_WriteString (&client->message, *s);
+	MSG_WriteByte (&client->message, 0);
+
+// send music
+	MSG_WriteByte (&client->message, svc_cdtrack);
+	MSG_WriteByte (&client->message, (int) sv.edicts->u.v.sounds);
+	MSG_WriteByte (&client->message, (int) sv.edicts->u.v.sounds);
+
+// set view	
+	MSG_WriteByte (&client->message, svc_setview);
+	MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict));
+
+	MSG_WriteByte (&client->message, svc_signonnum);
+	MSG_WriteByte (&client->message, 1);
+
+	client->sendsignon = true;
+	client->spawned = false;		// need prespawn, spawn, etc
+}
+
+/*
+================
+SV_ConnectClient
+
+Initializes a client_t for a new net connection.  This will only be called
+once for a player each game, not once for each level change.
+================
+*/
+void SV_ConnectClient (int clientnum)
+{
+	edict_t			*ent;
+	client_t		*client;
+	int				edictnum;
+	struct qsocket_s *netconnection;
+	int				i;
+	float			spawn_parms[NUM_SPAWN_PARMS];
+
+	client = svs.clients + clientnum;
+
+	Con_DPrintf ("Client %s connected\n", client->netconnection->address);
+
+	edictnum = clientnum+1;
+
+	ent = EDICT_NUM(edictnum);
+	
+// set up the client_t
+	netconnection = client->netconnection;
+	
+	if (sv.loadgame)
+		memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
+	memset (client, 0, sizeof(*client));
+	client->netconnection = netconnection;
+
+	strcpy (client->name, "unconnected");
+	client->active = true;
+	client->spawned = false;
+	client->edict = ent;
+	client->message.data = client->msgbuf;
+	client->message.maxsize = sizeof(client->msgbuf);
+	client->message.allowoverflow = true;		// we can catch it
+
+#ifdef IDGODS
+	client->privileged = IsID(&client->netconnection->addr);
+#else	
+	client->privileged = false;				
+#endif
+
+	if (sv.loadgame)
+		memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
+	else
+	{
+	// call the progs to get default spawn parms for the new client
+		PR_ExecuteProgram (pr_global_struct->SetNewParms);
+		for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
+			client->spawn_parms[i] = (&pr_global_struct->parm1)[i];
+	}
+
+	SV_SendServerinfo (client);
+}
+
+
+/*
+===================
+SV_CheckForNewClients
+
+===================
+*/
+void SV_CheckForNewClients (void)
+{
+	struct qsocket_s	*ret;
+	int				i;
+		
+//
+// check for new connections
+//
+	while (1)
+	{
+		ret = NET_CheckNewConnections ();
+		if (!ret)
+			break;
+
+	// 
+	// init a new client structure
+	//	
+		for (i=0 ; i<svs.maxclients ; i++)
+			if (!svs.clients[i].active)
+				break;
+		if (i == svs.maxclients)
+			Sys_Error ("Host_CheckForNewClients: no free clients");
+		
+		svs.clients[i].netconnection = ret;
+		SV_ConnectClient (i);	
+	
+		net_activeconnections++;
+	}
+}
+
+
+
+/*
+===============================================================================
+
+FRAME UPDATES
+
+===============================================================================
+*/
+
+/*
+==================
+SV_ClearDatagram
+
+==================
+*/
+void SV_ClearDatagram (void)
+{
+	SZ_Clear (&sv.datagram);
+}
+
+/*
+=============================================================================
+
+The PVS must include a small area around the client to allow head bobbing
+or other small motion on the client side.  Otherwise, a bob might cause an
+entity that should be visible to not show up, especially when the bob
+crosses a waterline.
+
+=============================================================================
+*/
+
+int		fatbytes;
+byte	fatpvs[MAX_MAP_LEAFS/8];
+
+void SV_AddToFatPVS (vec3_t org, mnode_t *node)
+{
+	int		i;
+	byte	*pvs;
+	mplane_t	*plane;
+	float	d;
+
+	while (1)
+	{
+	// if this is a leaf, accumulate the pvs bits
+		if (node->contents < 0)
+		{
+			if (node->contents != CONTENTS_SOLID)
+			{
+				pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel);
+				for (i=0 ; i<fatbytes ; i++)
+					fatpvs[i] |= pvs[i];
+			}
+			return;
+		}
+	
+		plane = node->plane;
+		d = DotProduct (org, plane->normal) - plane->dist;
+		if (d > 8)
+			node = node->children[0];
+		else if (d < -8)
+			node = node->children[1];
+		else
+		{	// go down both
+			SV_AddToFatPVS (org, node->children[0]);
+			node = node->children[1];
+		}
+	}
+}
+
+/*
+=============
+SV_FatPVS
+
+Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
+given point.
+=============
+*/
+byte *SV_FatPVS (vec3_t org)
+{
+	fatbytes = (sv.worldmodel->numleafs+31)>>3;
+	Q_memset (fatpvs, 0, fatbytes);
+	SV_AddToFatPVS (org, sv.worldmodel->nodes);
+	return fatpvs;
+}
+
+//=============================================================================
+
+
+/*
+=============
+SV_WriteEntitiesToClient
+
+=============
+*/
+void SV_WriteEntitiesToClient (edict_t	*clent, sizebuf_t *msg)
+{
+	int		e, i;
+	int		bits;
+	byte	*pvs;
+	vec3_t	org;
+	float	miss;
+	edict_t	*ent;
+
+// find the client's PVS
+	VectorAdd (clent->u.v.origin, clent->u.v.view_ofs, org);
+	pvs = SV_FatPVS (org);
+
+// send over all entities (excpet the client) that touch the pvs
+	ent = NEXT_EDICT(sv.edicts);
+	for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
+	{
+#ifdef QUAKE2
+		// don't send if flagged for NODRAW and there are no lighting effects
+		if (ent->u.v.effects == EF_NODRAW)
+			continue;
+#endif
+
+// ignore if not touching a PV leaf
+		if (ent != clent)	// clent is ALLWAYS sent
+		{
+// ignore ents without visible models
+			if (!ent->u.v.modelindex || !pr_strings[ent->u.v.model])
+				continue;
+
+			for (i=0 ; i < ent->num_leafs ; i++)
+				if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
+					break;
+				
+			if (i == ent->num_leafs)
+				continue;		// not visible
+		}
+
+		if (msg->maxsize - msg->cursize < 16)
+		{
+			Con_Printf ("packet overflow\n");
+			return;
+		}
+
+// send an update
+		bits = 0;
+		
+		for (i=0 ; i<3 ; i++)
+		{
+			miss = ent->u.v.origin[i] - ent->baseline.origin[i];
+			if ( miss < -0.1 || miss > 0.1 )
+				bits |= U_ORIGIN1<<i;
+		}
+
+		if ( ent->u.v.angles[0] != ent->baseline.angles[0] )
+			bits |= U_ANGLE1;
+			
+		if ( ent->u.v.angles[1] != ent->baseline.angles[1] )
+			bits |= U_ANGLE2;
+			
+		if ( ent->u.v.angles[2] != ent->baseline.angles[2] )
+			bits |= U_ANGLE3;
+			
+		if (ent->u.v.movetype == MOVETYPE_STEP)
+			bits |= U_NOLERP;	// don't mess up the step animation
+	
+		if (ent->baseline.colormap != ent->u.v.colormap)
+			bits |= U_COLORMAP;
+			
+		if (ent->baseline.skin != ent->u.v.skin)
+			bits |= U_SKIN;
+			
+		if (ent->baseline.frame != ent->u.v.frame)
+			bits |= U_FRAME;
+		
+		if (ent->baseline.effects != ent->u.v.effects)
+			bits |= U_EFFECTS;
+		
+		if (ent->baseline.modelindex != ent->u.v.modelindex)
+			bits |= U_MODEL;
+
+		if (e >= 256)
+			bits |= U_LONGENTITY;
+			
+		if (bits >= 256)
+			bits |= U_MOREBITS;
+
+	//
+	// write the message
+	//
+		MSG_WriteByte (msg,bits | U_SIGNAL);
+		
+		if (bits & U_MOREBITS)
+			MSG_WriteByte (msg, bits>>8);
+		if (bits & U_LONGENTITY)
+			MSG_WriteShort (msg,e);
+		else
+			MSG_WriteByte (msg,e);
+
+		if (bits & U_MODEL)
+			MSG_WriteByte (msg,	(int) ent->u.v.modelindex);
+		if (bits & U_FRAME)
+			MSG_WriteByte (msg, (int) ent->u.v.frame);
+		if (bits & U_COLORMAP)
+			MSG_WriteByte (msg, (int) ent->u.v.colormap);
+		if (bits & U_SKIN)
+			MSG_WriteByte (msg, (int) ent->u.v.skin);
+		if (bits & U_EFFECTS)
+			MSG_WriteByte (msg, (int) ent->u.v.effects);
+		if (bits & U_ORIGIN1)
+			MSG_WriteCoord (msg, ent->u.v.origin[0]);		
+		if (bits & U_ANGLE1)
+			MSG_WriteAngle(msg, ent->u.v.angles[0]);
+		if (bits & U_ORIGIN2)
+			MSG_WriteCoord (msg, ent->u.v.origin[1]);
+		if (bits & U_ANGLE2)
+			MSG_WriteAngle(msg, ent->u.v.angles[1]);
+		if (bits & U_ORIGIN3)
+			MSG_WriteCoord (msg, ent->u.v.origin[2]);
+		if (bits & U_ANGLE3)
+			MSG_WriteAngle(msg, ent->u.v.angles[2]);
+	}
+}
+
+/*
+=============
+SV_CleanupEnts
+
+=============
+*/
+void SV_CleanupEnts (void)
+{
+	int		e;
+	edict_t	*ent;
+	
+	ent = NEXT_EDICT(sv.edicts);
+	for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
+	{
+		ent->u.v.effects = (int)ent->u.v.effects & ~EF_MUZZLEFLASH;
+	}
+
+}
+
+/*
+==================
+SV_WriteClientdataToMessage
+
+==================
+*/
+void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
+{
+	int		bits;
+	int		i;
+	edict_t	*other;
+	int		items;
+#ifndef QUAKE2
+	eval_t	*val;
+#endif
+
+//
+// send a damage message
+//
+	if (ent->u.v.dmg_take || ent->u.v.dmg_save)
+	{
+		other = PROG_TO_EDICT(ent->u.v.dmg_inflictor);
+		MSG_WriteByte (msg, svc_damage);
+		MSG_WriteByte (msg, (int) ent->u.v.dmg_save);
+		MSG_WriteByte (msg, (int) ent->u.v.dmg_take);
+		for (i=0 ; i<3 ; i++)
+			MSG_WriteCoord (msg, other->u.v.origin[i] + 0.5*(other->u.v.mins[i] + other->u.v.maxs[i]));
+	
+		ent->u.v.dmg_take = 0;
+		ent->u.v.dmg_save = 0;
+	}
+
+//
+// send the current viewpos offset from the view entity
+//
+	SV_SetIdealPitch ();		// how much to look up / down ideally
+
+// a fixangle might get lost in a dropped packet.  Oh well.
+	if ( ent->u.v.fixangle )
+	{
+		MSG_WriteByte (msg, svc_setangle);
+		for (i=0 ; i < 3 ; i++)
+			MSG_WriteAngle (msg, ent->u.v.angles[i] );
+		ent->u.v.fixangle = 0;
+	}
+
+	bits = 0;
+	
+	if (ent->u.v.view_ofs[2] != DEFAULT_VIEWHEIGHT)
+		bits |= SU_VIEWHEIGHT;
+		
+	if (ent->u.v.idealpitch)
+		bits |= SU_IDEALPITCH;
+
+// stuff the sigil bits into the high bits of items for sbar, or else
+// mix in items2
+#ifdef QUAKE2
+	items = (int)ent->u.v.items | ((int)ent->u.v.items2 << 23);
+#else
+	val = GetEdictFieldValue(ent, "items2");
+
+	if (val)
+		items = (int)ent->u.v.items | ((int)val->_float << 23);
+	else
+		items = (int)ent->u.v.items | ((int)pr_global_struct->serverflags << 28);
+#endif
+
+	bits |= SU_ITEMS;
+	
+	if ( (int)ent->u.v.flags & FL_ONGROUND)
+		bits |= SU_ONGROUND;
+	
+	if ( ent->u.v.waterlevel >= 2)
+		bits |= SU_INWATER;
+	
+	for (i=0 ; i<3 ; i++)
+	{
+		if (ent->u.v.punchangle[i])
+			bits |= (SU_PUNCH1<<i);
+		if (ent->u.v.velocity[i])
+			bits |= (SU_VELOCITY1<<i);
+	}
+	
+	if (ent->u.v.weaponframe)
+		bits |= SU_WEAPONFRAME;
+
+	if (ent->u.v.armorvalue)
+		bits |= SU_ARMOR;
+
+//	if (ent->u.v.weapon)
+		bits |= SU_WEAPON;
+
+// send the data
+
+	MSG_WriteByte (msg, svc_clientdata);
+	MSG_WriteShort (msg, bits);
+
+	if (bits & SU_VIEWHEIGHT)
+		MSG_WriteChar (msg, (int) ent->u.v.view_ofs[2]);
+
+	if (bits & SU_IDEALPITCH)
+		MSG_WriteChar (msg, (int) ent->u.v.idealpitch);
+
+	for (i=0 ; i<3 ; i++)
+	{
+		if (bits & (SU_PUNCH1<<i))
+			MSG_WriteChar (msg, (int) ent->u.v.punchangle[i]);
+		if (bits & (SU_VELOCITY1<<i))
+			MSG_WriteChar (msg, (int) ent->u.v.velocity[i]/16);
+	}
+
+// [always sent]	if (bits & SU_ITEMS)
+	MSG_WriteLong (msg, items);
+
+	if (bits & SU_WEAPONFRAME)
+		MSG_WriteByte (msg, (int) ent->u.v.weaponframe);
+	if (bits & SU_ARMOR)
+		MSG_WriteByte (msg, (int) ent->u.v.armorvalue);
+	if (bits & SU_WEAPON)
+		MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->u.v.weaponmodel));
+	
+	MSG_WriteShort (msg, (int) ent->u.v.health);
+	MSG_WriteByte (msg, (int) ent->u.v.currentammo);
+	MSG_WriteByte (msg, (int) ent->u.v.ammo_shells);
+	MSG_WriteByte (msg, (int) ent->u.v.ammo_nails);
+	MSG_WriteByte (msg, (int) ent->u.v.ammo_rockets);
+	MSG_WriteByte (msg, (int) ent->u.v.ammo_cells);
+
+	if (standard_quake)
+	{
+		MSG_WriteByte (msg, (int) ent->u.v.weapon);
+	}
+	else
+	{
+		for(i=0;i<32;i++)
+		{
+			if ( ((int)ent->u.v.weapon) & (1<<i) )
+			{
+				MSG_WriteByte (msg, i);
+				break;
+			}
+		}
+	}
+}
+
+/*
+=======================
+SV_SendClientDatagram
+=======================
+*/
+qboolean SV_SendClientDatagram (client_t *client)
+{
+	byte		buf[MAX_DATAGRAM];
+	sizebuf_t	msg;
+	
+	msg.data = buf;
+	msg.maxsize = sizeof(buf);
+	msg.cursize = 0;
+
+	MSG_WriteByte (&msg, svc_time);
+	MSG_WriteFloat (&msg, sv.time);
+
+// add the client specific data to the datagram
+	SV_WriteClientdataToMessage (client->edict, &msg);
+
+	SV_WriteEntitiesToClient (client->edict, &msg);
+
+// copy the server datagram if there is space
+	if (msg.cursize + sv.datagram.cursize < msg.maxsize)
+		SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
+
+// send the datagram
+	if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)
+	{
+		SV_DropClient (true);// if the message couldn't send, kick off
+		return false;
+	}
+	
+	return true;
+}
+
+/*
+=======================
+SV_UpdateToReliableMessages
+=======================
+*/
+void SV_UpdateToReliableMessages (void)
+{
+	int			i, j;
+	client_t *client;
+
+// check for changes to be sent over the reliable streams
+	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
+	{
+		if (host_client->old_frags != host_client->edict->u.v.frags)
+		{
+			for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
+			{
+				if (!client->active)
+					continue;
+				MSG_WriteByte (&client->message, svc_updatefrags);
+				MSG_WriteByte (&client->message, i);
+				MSG_WriteShort (&client->message, (int) host_client->edict->u.v.frags);
+			}
+
+			host_client->old_frags = (int) host_client->edict->u.v.frags;
+		}
+	}
+	
+	for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
+	{
+		if (!client->active)
+			continue;
+		SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
+	}
+
+	SZ_Clear (&sv.reliable_datagram);
+}
+
+
+/*
+=======================
+SV_SendNop
+
+Send a nop message without trashing or sending the accumulated client
+message buffer
+=======================
+*/
+void SV_SendNop (client_t *client)
+{
+	sizebuf_t	msg;
+	byte		buf[4];
+	
+	msg.data = buf;
+	msg.maxsize = sizeof(buf);
+	msg.cursize = 0;
+
+	MSG_WriteChar (&msg, svc_nop);
+
+	if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)
+		SV_DropClient (true);	// if the message couldn't send, kick off
+	client->last_message = realtime;
+}
+
+/*
+=======================
+SV_SendClientMessages
+=======================
+*/
+void SV_SendClientMessages (void)
+{
+	int			i;
+	
+// update frags, names, etc
+	SV_UpdateToReliableMessages ();
+
+// build individual updates
+	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
+	{
+		if (!host_client->active)
+			continue;
+
+		if (host_client->spawned)
+		{
+			if (!SV_SendClientDatagram (host_client))
+				continue;
+		}
+		else
+		{
+		// the player isn't totally in the game yet
+		// send small keepalive messages if too much time has passed
+		// send a full message when the next signon stage has been requested
+		// some other message data (name changes, etc) may accumulate 
+		// between signon stages
+			if (!host_client->sendsignon)
+			{
+				if (realtime - host_client->last_message > 5)
+					SV_SendNop (host_client);
+				continue;	// don't send out non-signon messages
+			}
+		}
+
+		// check for an overflowed message.  Should only happen
+		// on a very fucked up connection that backs up a lot, then
+		// changes level
+		if (host_client->message.overflowed)
+		{
+			SV_DropClient (true);
+			host_client->message.overflowed = false;
+			continue;
+		}
+			
+		if (host_client->message.cursize || host_client->dropasap)
+		{
+			if (!NET_CanSendMessage (host_client->netconnection))
+			{
+//				I_Printf ("can't write\n");
+				continue;
+			}
+
+			if (host_client->dropasap)
+				SV_DropClient (false);	// went to another level
+			else
+			{
+				if (NET_SendMessage (host_client->netconnection
+				, &host_client->message) == -1)
+					SV_DropClient (true);	// if the message couldn't send, kick off
+				SZ_Clear (&host_client->message);
+				host_client->last_message = realtime;
+				host_client->sendsignon = false;
+			}
+		}
+	}
+	
+	
+// clear muzzle flashes
+	SV_CleanupEnts ();
+}
+
+
+/*
+==============================================================================
+
+SERVER SPAWNING
+
+==============================================================================
+*/
+
+/*
+================
+SV_ModelIndex
+
+================
+*/
+int SV_ModelIndex (const char *name)
+{
+	int		i;
+	
+	if (!name || !name[0])
+		return 0;
+
+	for (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++)
+		if (!strcmp(sv.model_precache[i], name))
+			return i;
+	if (i==MAX_MODELS || !sv.model_precache[i])
+		Sys_Error ("SV_ModelIndex: model %s not precached", name);
+	return i;
+}
+
+/*
+================
+SV_CreateBaseline
+
+================
+*/
+void SV_CreateBaseline (void)
+{
+	int			i;
+	edict_t			*svent;
+	int				entnum;	
+		
+	for (entnum = 0; entnum < sv.num_edicts ; entnum++)
+	{
+	// get the current server version
+		svent = EDICT_NUM(entnum);
+		if (svent->free)
+			continue;
+		if (entnum > svs.maxclients && !svent->u.v.modelindex)
+			continue;
+
+	//
+	// create entity baseline
+	//
+		VectorCopy (svent->u.v.origin, svent->baseline.origin);
+		VectorCopy (svent->u.v.angles, svent->baseline.angles);
+		svent->baseline.frame = (int) svent->u.v.frame;
+		svent->baseline.skin = (int) svent->u.v.skin;
+		if (entnum > 0 && entnum <= svs.maxclients)
+		{
+			svent->baseline.colormap = entnum;
+			svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
+		}
+		else
+		{
+			svent->baseline.colormap = 0;
+			svent->baseline.modelindex =
+				SV_ModelIndex(pr_strings + svent->u.v.model);
+		}
+		
+	//
+	// add to the message
+	//
+		MSG_WriteByte (&sv.signon,svc_spawnbaseline);		
+		MSG_WriteShort (&sv.signon,entnum);
+
+		MSG_WriteByte (&sv.signon, svent->baseline.modelindex);
+		MSG_WriteByte (&sv.signon, svent->baseline.frame);
+		MSG_WriteByte (&sv.signon, svent->baseline.colormap);
+		MSG_WriteByte (&sv.signon, svent->baseline.skin);
+		for (i=0 ; i<3 ; i++)
+		{
+			MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]);
+			MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);
+		}
+	}
+}
+
+
+/*
+================
+SV_SendReconnect
+
+Tell all the clients that the server is changing levels
+================
+*/
+void SV_SendReconnect (void)
+{
+	char	data[128];
+	sizebuf_t	msg;
+
+	msg.data = (byte*) data;
+	msg.cursize = 0;
+	msg.maxsize = sizeof(data);
+
+	MSG_WriteChar (&msg, svc_stufftext);
+	MSG_WriteString (&msg, "reconnect\n");
+	NET_SendToAll (&msg, 5);
+	
+	if (cls.state != ca_dedicated)
+#ifdef QUAKE2
+		Cbuf_InsertText ("reconnect\n");
+#else
+		Cmd_ExecuteString2 ("reconnect\n", src_command);
+#endif
+}
+
+
+/*
+================
+SV_SaveSpawnparms
+
+Grabs the current state of each client for saving across the
+transition to another level
+================
+*/
+void SV_SaveSpawnparms (void)
+{
+	int		i, j;
+
+	svs.serverflags = (int) pr_global_struct->serverflags;
+
+	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
+	{
+		if (!host_client->active)
+			continue;
+
+	// call the progs to get default spawn parms for the new client
+		pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+		PR_ExecuteProgram (pr_global_struct->SetChangeParms);
+		for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
+			host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j];
+	}
+}
+
+
+/*
+================
+SV_SpawnServer
+
+This is called at the start of each level
+================
+*/
+extern float		scr_centertime_off;
+
+#ifdef QUAKE2
+void SV_SpawnServer (char *server, char *startspot)
+#else
+void SV_SpawnServer (char *server)
+#endif
+{
+	edict_t		*ent;
+	int			i;
+
+	// let's not have any servers with no name
+	if (hostname.string[0] == 0)
+		Cvar_Set ("hostname", "UNNAMED");
+	scr_centertime_off = 0;
+
+	Con_DPrintf ("SpawnServer: %s\n",server);
+	svs.changelevel_issued = false;		// now safe to issue another
+
+//
+// tell all connected clients that we are going to a new level
+//
+	if (sv.active)
+	{
+		SV_SendReconnect ();
+	}
+
+//
+// make cvars consistant
+//
+	if (coop.value)
+		Cvar_SetValue ("deathmatch", 0);
+	current_skill = (int)(skill.value + 0.5);
+	if (current_skill < 0)
+		current_skill = 0;
+	if (current_skill > 3)
+		current_skill = 3;
+
+	Cvar_SetValue ("skill", (float)current_skill);
+	
+//
+// set up the new server
+//
+	Host_ClearMemory ();
+
+	memset (&sv, 0, sizeof(sv));
+
+	strcpy (sv.name, server);
+#ifdef QUAKE2
+	if (startspot)
+		strcpy(sv.startspot, startspot);
+#endif
+
+// load progs to get entity field count
+	PR_LoadProgs ();
+
+// allocate server memory
+	sv.max_edicts = MAX_EDICTS;
+	
+	sv.edicts = (edict_t*) Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts");
+
+	sv.datagram.maxsize = sizeof(sv.datagram_buf);
+	sv.datagram.cursize = 0;
+	sv.datagram.data = sv.datagram_buf;
+	
+	sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
+	sv.reliable_datagram.cursize = 0;
+	sv.reliable_datagram.data = sv.reliable_datagram_buf;
+	
+	sv.signon.maxsize = sizeof(sv.signon_buf);
+	sv.signon.cursize = 0;
+	sv.signon.data = sv.signon_buf;
+	
+// leave slots at start for clients only
+	sv.num_edicts = svs.maxclients+1;
+	for (i=0 ; i<svs.maxclients ; i++)
+	{
+		ent = EDICT_NUM(i+1);
+		svs.clients[i].edict = ent;
+	}
+	
+	sv.state = ss_loading;
+	sv.paused = false;
+
+	sv.time = 1.0;
+	
+	strcpy (sv.name, server);
+	sprintf (sv.modelname,"maps/%s.bsp", server);
+	sv.worldmodel = Mod_ForName (sv.modelname, false);
+	if (!sv.worldmodel)
+	{
+		Con_Printf ("Couldn't spawn server %s\n", sv.modelname);
+		sv.active = false;
+		return;
+	}
+	sv.models[1] = sv.worldmodel;
+	
+//
+// clear world interaction links
+//
+	SV_ClearWorld ();
+	
+	sv.sound_precache[0] = pr_strings;
+
+	sv.model_precache[0] = pr_strings;
+	sv.model_precache[1] = sv.modelname;
+	for (i=1 ; i<sv.worldmodel->numsubmodels ; i++)
+	{
+		sv.model_precache[1+i] = localmodels[i];
+		sv.models[i+1] = Mod_ForName (localmodels[i], false);
+	}
+
+//
+// load the rest of the entities
+//	
+	ent = EDICT_NUM(0);
+	memset (&ent->u.v, 0, progs->entityfields * 4);
+	ent->free = false;
+	ent->u.v.model = sv.worldmodel->name - pr_strings;
+	ent->u.v.modelindex = 1;		// world model
+	ent->u.v.solid = SOLID_BSP;
+	ent->u.v.movetype = MOVETYPE_PUSH;
+
+	if (coop.value)
+		pr_global_struct->coop = coop.value;
+	else
+		pr_global_struct->deathmatch = deathmatch.value;
+
+	pr_global_struct->mapname = sv.name - pr_strings;
+#ifdef QUAKE2
+	pr_global_struct->startspot = sv.startspot - pr_strings;
+#endif
+
+// serverflags are for cross level information (sigils)
+	pr_global_struct->serverflags = svs.serverflags;
+	
+	ED_LoadFromFile (sv.worldmodel->entities);
+
+	sv.active = true;
+
+// all setup is completed, any further precache statements are errors
+	sv.state = ss_active;
+	
+// run two frames to allow everything to settle
+	host_frametime = 0.1;
+	SV_Physics ();
+	SV_Physics ();
+
+// create a baseline for more efficient communications
+	SV_CreateBaseline ();
+
+// send serverinfo to all connected clients
+	for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
+		if (host_client->active)
+			SV_SendServerinfo (host_client);
+	
+	Con_DPrintf ("Server spawned.\n");
+}
+
diff --git a/quake/src/WinQuake/sv_move.c b/quake/src/WinQuake/sv_move.cpp
old mode 100644
new mode 100755
similarity index 77%
rename from quake/src/WinQuake/sv_move.c
rename to quake/src/WinQuake/sv_move.cpp
index fd967f9..5832128
--- a/quake/src/WinQuake/sv_move.c
+++ b/quake/src/WinQuake/sv_move.cpp
@@ -1,427 +1,427 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// sv_move.c -- monster movement

-

-#include "quakedef.h"

-

-#define	STEPSIZE	18

-

-/*

-=============

-SV_CheckBottom

-

-Returns false if any part of the bottom of the entity is off an edge that

-is not a staircase.

-

-=============

-*/

-int c_yes, c_no;

-

-qboolean SV_CheckBottom (edict_t *ent)

-{

-	vec3_t	mins, maxs, start, stop;

-	trace_t	trace;

-	int		x, y;

-	float	mid, bottom;

-	

-	VectorAdd (ent->v.origin, ent->v.mins, mins);

-	VectorAdd (ent->v.origin, ent->v.maxs, maxs);

-

-// if all of the points under the corners are solid world, don't bother

-// with the tougher checks

-// the corners must be within 16 of the midpoint

-	start[2] = mins[2] - 1;

-	for	(x=0 ; x<=1 ; x++)

-		for	(y=0 ; y<=1 ; y++)

-		{

-			start[0] = x ? maxs[0] : mins[0];

-			start[1] = y ? maxs[1] : mins[1];

-			if (SV_PointContents (start) != CONTENTS_SOLID)

-				goto realcheck;

-		}

-

-	c_yes++;

-	return true;		// we got out easy

-

-realcheck:

-	c_no++;

-//

-// check it for real...

-//

-	start[2] = mins[2];

-	

-// the midpoint must be within 16 of the bottom

-	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;

-	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;

-	stop[2] = start[2] - 2*STEPSIZE;

-	trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);

-

-	if (trace.fraction == 1.0)

-		return false;

-	mid = bottom = trace.endpos[2];

-	

-// the corners must be within 16 of the midpoint	

-	for	(x=0 ; x<=1 ; x++)

-		for	(y=0 ; y<=1 ; y++)

-		{

-			start[0] = stop[0] = x ? maxs[0] : mins[0];

-			start[1] = stop[1] = y ? maxs[1] : mins[1];

-			

-			trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);

-			

-			if (trace.fraction != 1.0 && trace.endpos[2] > bottom)

-				bottom = trace.endpos[2];

-			if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)

-				return false;

-		}

-

-	c_yes++;

-	return true;

-}

-

-

-/*

-=============

-SV_movestep

-

-Called by monster program code.

-The move will be adjusted for slopes and stairs, but if the move isn't

-possible, no move is done, false is returned, and

-pr_global_struct->trace_normal is set to the normal of the blocking wall

-=============

-*/

-qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)

-{

-	float		dz;

-	vec3_t		oldorg, neworg, end;

-	trace_t		trace;

-	int			i;

-	edict_t		*enemy;

-

-// try the move	

-	VectorCopy (ent->v.origin, oldorg);

-	VectorAdd (ent->v.origin, move, neworg);

-

-// flying monsters don't step up

-	if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )

-	{

-	// try one move with vertical motion, then one without

-		for (i=0 ; i<2 ; i++)

-		{

-			VectorAdd (ent->v.origin, move, neworg);

-			enemy = PROG_TO_EDICT(ent->v.enemy);

-			if (i == 0 && enemy != sv.edicts)

-			{

-				dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];

-				if (dz > 40)

-					neworg[2] -= 8;

-				if (dz < 30)

-					neworg[2] += 8;

-			}

-			trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent);

-	

-			if (trace.fraction == 1)

-			{

-				if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )

-					return false;	// swim monster left water

-	

-				VectorCopy (trace.endpos, ent->v.origin);

-				if (relink)

-					SV_LinkEdict (ent, true);

-				return true;

-			}

-			

-			if (enemy == sv.edicts)

-				break;

-		}

-		

-		return false;

-	}

-

-// push down from a step height above the wished position

-	neworg[2] += STEPSIZE;

-	VectorCopy (neworg, end);

-	end[2] -= STEPSIZE*2;

-

-	trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent);

-

-	if (trace.allsolid)

-		return false;

-

-	if (trace.startsolid)

-	{

-		neworg[2] -= STEPSIZE;

-		trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent);

-		if (trace.allsolid || trace.startsolid)

-			return false;

-	}

-	if (trace.fraction == 1)

-	{

-	// if monster had the ground pulled out, go ahead and fall

-		if ( (int)ent->v.flags & FL_PARTIALGROUND )

-		{

-			VectorAdd (ent->v.origin, move, ent->v.origin);

-			if (relink)

-				SV_LinkEdict (ent, true);

-			ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;

-//	Con_Printf ("fall down\n"); 

-			return true;

-		}

-	

-		return false;		// walked off an edge

-	}

-

-// check point traces down for dangling corners

-	VectorCopy (trace.endpos, ent->v.origin);

-	

-	if (!SV_CheckBottom (ent))

-	{

-		if ( (int)ent->v.flags & FL_PARTIALGROUND )

-		{	// entity had floor mostly pulled out from underneath it

-			// and is trying to correct

-			if (relink)

-				SV_LinkEdict (ent, true);

-			return true;

-		}

-		VectorCopy (oldorg, ent->v.origin);

-		return false;

-	}

-

-	if ( (int)ent->v.flags & FL_PARTIALGROUND )

-	{

-//		Con_Printf ("back on ground\n"); 

-		ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;

-	}

-	ent->v.groundentity = EDICT_TO_PROG(trace.ent);

-

-// the move is ok

-	if (relink)

-		SV_LinkEdict (ent, true);

-	return true;

-}

-

-

-//============================================================================

-

-/*

-======================

-SV_StepDirection

-

-Turns to the movement direction, and walks the current distance if

-facing it.

-

-======================

-*/

-void PF_changeyaw (void);

-qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)

-{

-	vec3_t		move, oldorigin;

-	float		delta;

-	

-	ent->v.ideal_yaw = yaw;

-	PF_changeyaw();

-	

-	yaw = yaw*M_PI*2 / 360;

-	move[0] = cos(yaw)*dist;

-	move[1] = sin(yaw)*dist;

-	move[2] = 0;

-

-	VectorCopy (ent->v.origin, oldorigin);

-	if (SV_movestep (ent, move, false))

-	{

-		delta = ent->v.angles[YAW] - ent->v.ideal_yaw;

-		if (delta > 45 && delta < 315)

-		{		// not turned far enough, so don't take the step

-			VectorCopy (oldorigin, ent->v.origin);

-		}

-		SV_LinkEdict (ent, true);

-		return true;

-	}

-	SV_LinkEdict (ent, true);

-		

-	return false;

-}

-

-/*

-======================

-SV_FixCheckBottom

-

-======================

-*/

-void SV_FixCheckBottom (edict_t *ent)

-{

-//	Con_Printf ("SV_FixCheckBottom\n");

-	

-	ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;

-}

-

-

-

-/*

-================

-SV_NewChaseDir

-

-================

-*/

-#define	DI_NODIR	-1

-void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)

-{

-	float		deltax,deltay;

-	float			d[3];

-	float		tdir, olddir, turnaround;

-

-	olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 );

-	turnaround = anglemod(olddir - 180);

-

-	deltax = enemy->v.origin[0] - actor->v.origin[0];

-	deltay = enemy->v.origin[1] - actor->v.origin[1];

-	if (deltax>10)

-		d[1]= 0;

-	else if (deltax<-10)

-		d[1]= 180;

-	else

-		d[1]= DI_NODIR;

-	if (deltay<-10)

-		d[2]= 270;

-	else if (deltay>10)

-		d[2]= 90;

-	else

-		d[2]= DI_NODIR;

-

-// try direct route

-	if (d[1] != DI_NODIR && d[2] != DI_NODIR)

-	{

-		if (d[1] == 0)

-			tdir = d[2] == 90 ? 45 : 315;

-		else

-			tdir = d[2] == 90 ? 135 : 215;

-			

-		if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))

-			return;

-	}

-

-// try other directions

-	if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))

-	{

-		tdir=d[1];

-		d[1]=d[2];

-		d[2]=tdir;

-	}

-

-	if (d[1]!=DI_NODIR && d[1]!=turnaround 

-	&& SV_StepDirection(actor, d[1], dist))

-			return;

-

-	if (d[2]!=DI_NODIR && d[2]!=turnaround

-	&& SV_StepDirection(actor, d[2], dist))

-			return;

-

-/* there is no direct path to the player, so pick another direction */

-

-	if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))

-			return;

-

-	if (rand()&1) 	/*randomly determine direction of search*/

-	{

-		for (tdir=0 ; tdir<=315 ; tdir += 45)

-			if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )

-					return;

-	}

-	else

-	{

-		for (tdir=315 ; tdir >=0 ; tdir -= 45)

-			if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )

-					return;

-	}

-

-	if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )

-			return;

-

-	actor->v.ideal_yaw = olddir;		// can't move

-

-// if a bridge was pulled out from underneath a monster, it may not have

-// a valid standing position at all

-

-	if (!SV_CheckBottom (actor))

-		SV_FixCheckBottom (actor);

-

-}

-

-/*

-======================

-SV_CloseEnough

-

-======================

-*/

-qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)

-{

-	int		i;

-	

-	for (i=0 ; i<3 ; i++)

-	{

-		if (goal->v.absmin[i] > ent->v.absmax[i] + dist)

-			return false;

-		if (goal->v.absmax[i] < ent->v.absmin[i] - dist)

-			return false;

-	}

-	return true;

-}

-

-/*

-======================

-SV_MoveToGoal

-

-======================

-*/

-void SV_MoveToGoal (void)

-{

-	edict_t		*ent, *goal;

-	float		dist;

-#ifdef QUAKE2

-	edict_t		*enemy;

-#endif

-

-	ent = PROG_TO_EDICT(pr_global_struct->self);

-	goal = PROG_TO_EDICT(ent->v.goalentity);

-	dist = G_FLOAT(OFS_PARM0);

-

-	if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )

-	{

-		G_FLOAT(OFS_RETURN) = 0;

-		return;

-	}

-

-// if the next step hits the enemy, return immediately

-#ifdef QUAKE2

-	enemy = PROG_TO_EDICT(ent->v.enemy);

-	if (enemy != sv.edicts &&  SV_CloseEnough (ent, enemy, dist) )

-#else

-	if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts &&  SV_CloseEnough (ent, goal, dist) )

-#endif

-		return;

-

-// bump around...

-	if ( (rand()&3)==1 ||

-	!SV_StepDirection (ent, ent->v.ideal_yaw, dist))

-	{

-		SV_NewChaseDir (ent, goal, dist);

-	}

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// sv_move.c -- monster movement
+
+#include "quakedef.h"
+
+#define	STEPSIZE	18
+
+/*
+=============
+SV_CheckBottom
+
+Returns false if any part of the bottom of the entity is off an edge that
+is not a staircase.
+
+=============
+*/
+int c_yes, c_no;
+
+qboolean SV_CheckBottom (edict_t *ent)
+{
+	vec3_t	mins, maxs, start, stop;
+	trace_t	trace;
+	int		x, y;
+	float	mid, bottom;
+	
+	VectorAdd (ent->u.v.origin, ent->u.v.mins, mins);
+	VectorAdd (ent->u.v.origin, ent->u.v.maxs, maxs);
+
+// if all of the points under the corners are solid world, don't bother
+// with the tougher checks
+// the corners must be within 16 of the midpoint
+	start[2] = mins[2] - 1;
+	for	(x=0 ; x<=1 ; x++)
+		for	(y=0 ; y<=1 ; y++)
+		{
+			start[0] = x ? maxs[0] : mins[0];
+			start[1] = y ? maxs[1] : mins[1];
+			if (SV_PointContents (start) != CONTENTS_SOLID)
+				goto realcheck;
+		}
+
+	c_yes++;
+	return true;		// we got out easy
+
+realcheck:
+	c_no++;
+//
+// check it for real...
+//
+	start[2] = mins[2];
+	
+// the midpoint must be within 16 of the bottom
+	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
+	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
+	stop[2] = start[2] - 2*STEPSIZE;
+	trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);
+
+	if (trace.fraction == 1.0)
+		return false;
+	mid = bottom = trace.endpos[2];
+	
+// the corners must be within 16 of the midpoint	
+	for	(x=0 ; x<=1 ; x++)
+		for	(y=0 ; y<=1 ; y++)
+		{
+			start[0] = stop[0] = x ? maxs[0] : mins[0];
+			start[1] = stop[1] = y ? maxs[1] : mins[1];
+			
+			trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);
+			
+			if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
+				bottom = trace.endpos[2];
+			if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
+				return false;
+		}
+
+	c_yes++;
+	return true;
+}
+
+
+/*
+=============
+SV_movestep
+
+Called by monster program code.
+The move will be adjusted for slopes and stairs, but if the move isn't
+possible, no move is done, false is returned, and
+pr_global_struct->trace_normal is set to the normal of the blocking wall
+=============
+*/
+qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
+{
+	float		dz;
+	vec3_t		oldorg, neworg, end;
+	trace_t		trace;
+	int			i;
+	edict_t		*enemy;
+
+// try the move	
+	VectorCopy (ent->u.v.origin, oldorg);
+	VectorAdd (ent->u.v.origin, move, neworg);
+
+// flying monsters don't step up
+	if ( (int)ent->u.v.flags & (FL_SWIM | FL_FLY) )
+	{
+	// try one move with vertical motion, then one without
+		for (i=0 ; i<2 ; i++)
+		{
+			VectorAdd (ent->u.v.origin, move, neworg);
+			enemy = PROG_TO_EDICT(ent->u.v.enemy);
+			if (i == 0 && enemy != sv.edicts)
+			{
+				dz = ent->u.v.origin[2] - PROG_TO_EDICT(ent->u.v.enemy)->u.v.origin[2];
+				if (dz > 40)
+					neworg[2] -= 8;
+				if (dz < 30)
+					neworg[2] += 8;
+			}
+			trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, neworg, false, ent);
+	
+			if (trace.fraction == 1)
+			{
+				if ( ((int)ent->u.v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
+					return false;	// swim monster left water
+	
+				VectorCopy (trace.endpos, ent->u.v.origin);
+				if (relink)
+					SV_LinkEdict (ent, true);
+				return true;
+			}
+			
+			if (enemy == sv.edicts)
+				break;
+		}
+		
+		return false;
+	}
+
+// push down from a step height above the wished position
+	neworg[2] += STEPSIZE;
+	VectorCopy (neworg, end);
+	end[2] -= STEPSIZE*2;
+
+	trace = SV_Move (neworg, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
+
+	if (trace.allsolid)
+		return false;
+
+	if (trace.startsolid)
+	{
+		neworg[2] -= STEPSIZE;
+		trace = SV_Move (neworg, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
+		if (trace.allsolid || trace.startsolid)
+			return false;
+	}
+	if (trace.fraction == 1)
+	{
+	// if monster had the ground pulled out, go ahead and fall
+		if ( (int)ent->u.v.flags & FL_PARTIALGROUND )
+		{
+			VectorAdd (ent->u.v.origin, move, ent->u.v.origin);
+			if (relink)
+				SV_LinkEdict (ent, true);
+			ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
+//	Con_Printf ("fall down\n"); 
+			return true;
+		}
+	
+		return false;		// walked off an edge
+	}
+
+// check point traces down for dangling corners
+	VectorCopy (trace.endpos, ent->u.v.origin);
+	
+	if (!SV_CheckBottom (ent))
+	{
+		if ( (int)ent->u.v.flags & FL_PARTIALGROUND )
+		{	// entity had floor mostly pulled out from underneath it
+			// and is trying to correct
+			if (relink)
+				SV_LinkEdict (ent, true);
+			return true;
+		}
+		VectorCopy (oldorg, ent->u.v.origin);
+		return false;
+	}
+
+	if ( (int)ent->u.v.flags & FL_PARTIALGROUND )
+	{
+//		Con_Printf ("back on ground\n"); 
+		ent->u.v.flags = (int)ent->u.v.flags & ~FL_PARTIALGROUND;
+	}
+	ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
+
+// the move is ok
+	if (relink)
+		SV_LinkEdict (ent, true);
+	return true;
+}
+
+
+//============================================================================
+
+/*
+======================
+SV_StepDirection
+
+Turns to the movement direction, and walks the current distance if
+facing it.
+
+======================
+*/
+void PF_changeyaw (void);
+qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
+{
+	vec3_t		move, oldorigin;
+	float		delta;
+	
+	ent->u.v.ideal_yaw = yaw;
+	PF_changeyaw();
+	
+	yaw = yaw*M_PI*2 / 360;
+	move[0] = cos(yaw)*dist;
+	move[1] = sin(yaw)*dist;
+	move[2] = 0;
+
+	VectorCopy (ent->u.v.origin, oldorigin);
+	if (SV_movestep (ent, move, false))
+	{
+		delta = ent->u.v.angles[YAW] - ent->u.v.ideal_yaw;
+		if (delta > 45 && delta < 315)
+		{		// not turned far enough, so don't take the step
+			VectorCopy (oldorigin, ent->u.v.origin);
+		}
+		SV_LinkEdict (ent, true);
+		return true;
+	}
+	SV_LinkEdict (ent, true);
+		
+	return false;
+}
+
+/*
+======================
+SV_FixCheckBottom
+
+======================
+*/
+void SV_FixCheckBottom (edict_t *ent)
+{
+//	Con_Printf ("SV_FixCheckBottom\n");
+	
+	ent->u.v.flags = (int)ent->u.v.flags | FL_PARTIALGROUND;
+}
+
+
+
+/*
+================
+SV_NewChaseDir
+
+================
+*/
+#define	DI_NODIR	-1
+void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
+{
+	float		deltax,deltay;
+	float			d[3];
+	float		tdir, olddir, turnaround;
+
+	olddir = anglemod( (int)(actor->u.v.ideal_yaw/45)*45 );
+	turnaround = anglemod(olddir - 180);
+
+	deltax = enemy->u.v.origin[0] - actor->u.v.origin[0];
+	deltay = enemy->u.v.origin[1] - actor->u.v.origin[1];
+	if (deltax>10)
+		d[1]= 0;
+	else if (deltax<-10)
+		d[1]= 180;
+	else
+		d[1]= DI_NODIR;
+	if (deltay<-10)
+		d[2]= 270;
+	else if (deltay>10)
+		d[2]= 90;
+	else
+		d[2]= DI_NODIR;
+
+// try direct route
+	if (d[1] != DI_NODIR && d[2] != DI_NODIR)
+	{
+		if (d[1] == 0)
+			tdir = d[2] == 90 ? 45 : 315;
+		else
+			tdir = d[2] == 90 ? 135 : 215;
+			
+		if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
+			return;
+	}
+
+// try other directions
+	if ( ((rand()&3) & 1) ||  abs((int) deltay)>abs((int) deltax))
+	{
+		tdir=d[1];
+		d[1]=d[2];
+		d[2]=tdir;
+	}
+
+	if (d[1]!=DI_NODIR && d[1]!=turnaround 
+	&& SV_StepDirection(actor, d[1], dist))
+			return;
+
+	if (d[2]!=DI_NODIR && d[2]!=turnaround
+	&& SV_StepDirection(actor, d[2], dist))
+			return;
+
+/* there is no direct path to the player, so pick another direction */
+
+	if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
+			return;
+
+	if (rand()&1) 	/*randomly determine direction of search*/
+	{
+		for (tdir=0 ; tdir<=315 ; tdir += 45)
+			if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
+					return;
+	}
+	else
+	{
+		for (tdir=315 ; tdir >=0 ; tdir -= 45)
+			if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
+					return;
+	}
+
+	if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
+			return;
+
+	actor->u.v.ideal_yaw = olddir;		// can't move
+
+// if a bridge was pulled out from underneath a monster, it may not have
+// a valid standing position at all
+
+	if (!SV_CheckBottom (actor))
+		SV_FixCheckBottom (actor);
+
+}
+
+/*
+======================
+SV_CloseEnough
+
+======================
+*/
+qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
+{
+	int		i;
+	
+	for (i=0 ; i<3 ; i++)
+	{
+		if (goal->u.v.absmin[i] > ent->u.v.absmax[i] + dist)
+			return false;
+		if (goal->u.v.absmax[i] < ent->u.v.absmin[i] - dist)
+			return false;
+	}
+	return true;
+}
+
+/*
+======================
+SV_MoveToGoal
+
+======================
+*/
+void SV_MoveToGoal (void)
+{
+	edict_t		*ent, *goal;
+	float		dist;
+#ifdef QUAKE2
+	edict_t		*enemy;
+#endif
+
+	ent = PROG_TO_EDICT(pr_global_struct->self);
+	goal = PROG_TO_EDICT(ent->u.v.goalentity);
+	dist = G_FLOAT(OFS_PARM0);
+
+	if ( !( (int)ent->u.v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+	{
+		G_FLOAT(OFS_RETURN) = 0;
+		return;
+	}
+
+// if the next step hits the enemy, return immediately
+#ifdef QUAKE2
+	enemy = PROG_TO_EDICT(ent->u.v.enemy);
+	if (enemy != sv.edicts &&  SV_CloseEnough (ent, enemy, dist) )
+#else
+	if ( PROG_TO_EDICT(ent->u.v.enemy) != sv.edicts &&  SV_CloseEnough (ent, goal, dist) )
+#endif
+		return;
+
+// bump around...
+	if ( (rand()&3)==1 ||
+	!SV_StepDirection (ent, ent->u.v.ideal_yaw, dist))
+	{
+		SV_NewChaseDir (ent, goal, dist);
+	}
+}
+
diff --git a/quake/src/WinQuake/sv_phys.c b/quake/src/WinQuake/sv_phys.cpp
old mode 100644
new mode 100755
similarity index 63%
rename from quake/src/WinQuake/sv_phys.c
rename to quake/src/WinQuake/sv_phys.cpp
index 1e3cc73..ebc1ef7
--- a/quake/src/WinQuake/sv_phys.c
+++ b/quake/src/WinQuake/sv_phys.cpp
@@ -1,1617 +1,1617 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// sv_phys.c

-

-#include "quakedef.h"

-

-/*

-

-

-pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.

-

-onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects 

-

-doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH

-bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS

-corpses are SOLID_NOT and MOVETYPE_TOSS

-crates are SOLID_BBOX and MOVETYPE_TOSS

-walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP

-flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY

-

-solid_edge items only clip against bsp models.

-

-*/

-

-cvar_t	sv_friction = {"sv_friction","4",false,true};

-cvar_t	sv_stopspeed = {"sv_stopspeed","100"};

-cvar_t	sv_gravity = {"sv_gravity","800",false,true};

-cvar_t	sv_maxvelocity = {"sv_maxvelocity","2000"};

-cvar_t	sv_nostep = {"sv_nostep","0"};

-

-#ifdef QUAKE2

-static	vec3_t	vec_origin = {0.0, 0.0, 0.0};

-#endif

-

-#define	MOVE_EPSILON	0.01

-

-void SV_Physics_Toss (edict_t *ent);

-

-/*

-================

-SV_CheckAllEnts

-================

-*/

-void SV_CheckAllEnts (void)

-{

-	int			e;

-	edict_t		*check;

-

-// see if any solid entities are inside the final position

-	check = NEXT_EDICT(sv.edicts);

-	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))

-	{

-		if (check->free)

-			continue;

-		if (check->v.movetype == MOVETYPE_PUSH

-		|| check->v.movetype == MOVETYPE_NONE

-#ifdef QUAKE2

-		|| check->v.movetype == MOVETYPE_FOLLOW

-#endif

-		|| check->v.movetype == MOVETYPE_NOCLIP)

-			continue;

-

-		if (SV_TestEntityPosition (check))

-			Con_Printf ("entity in invalid position\n");

-	}

-}

-

-/*

-================

-SV_CheckVelocity

-================

-*/

-void SV_CheckVelocity (edict_t *ent)

-{

-	int		i;

-

-//

-// bound velocity

-//

-	for (i=0 ; i<3 ; i++)

-	{

-		if (IS_NAN(ent->v.velocity[i]))

-		{

-			Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);

-			ent->v.velocity[i] = 0;

-		}

-		if (IS_NAN(ent->v.origin[i]))

-		{

-			Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);

-			ent->v.origin[i] = 0;

-		}

-		if (ent->v.velocity[i] > sv_maxvelocity.value)

-			ent->v.velocity[i] = sv_maxvelocity.value;

-		else if (ent->v.velocity[i] < -sv_maxvelocity.value)

-			ent->v.velocity[i] = -sv_maxvelocity.value;

-	}

-}

-

-/*

-=============

-SV_RunThink

-

-Runs thinking code if time.  There is some play in the exact time the think

-function will be called, because it is called before any movement is done

-in a frame.  Not used for pushmove objects, because they must be exact.

-Returns false if the entity removed itself.

-=============

-*/

-qboolean SV_RunThink (edict_t *ent)

-{

-	float	thinktime;

-

-	thinktime = ent->v.nextthink;

-	if (thinktime <= 0 || thinktime > sv.time + host_frametime)

-		return true;

-		

-	if (thinktime < sv.time)

-		thinktime = sv.time;	// don't let things stay in the past.

-								// it is possible to start that way

-								// by a trigger with a local time.

-	ent->v.nextthink = 0;

-	pr_global_struct->time = thinktime;

-	pr_global_struct->self = EDICT_TO_PROG(ent);

-	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);

-	PR_ExecuteProgram (ent->v.think);

-	return !ent->free;

-}

-

-/*

-==================

-SV_Impact

-

-Two entities have touched, so run their touch functions

-==================

-*/

-void SV_Impact (edict_t *e1, edict_t *e2)

-{

-	int		old_self, old_other;

-	

-	old_self = pr_global_struct->self;

-	old_other = pr_global_struct->other;

-	

-	pr_global_struct->time = sv.time;

-	if (e1->v.touch && e1->v.solid != SOLID_NOT)

-	{

-		pr_global_struct->self = EDICT_TO_PROG(e1);

-		pr_global_struct->other = EDICT_TO_PROG(e2);

-		PR_ExecuteProgram (e1->v.touch);

-	}

-	

-	if (e2->v.touch && e2->v.solid != SOLID_NOT)

-	{

-		pr_global_struct->self = EDICT_TO_PROG(e2);

-		pr_global_struct->other = EDICT_TO_PROG(e1);

-		PR_ExecuteProgram (e2->v.touch);

-	}

-

-	pr_global_struct->self = old_self;

-	pr_global_struct->other = old_other;

-}

-

-

-/*

-==================

-ClipVelocity

-

-Slide off of the impacting object

-returns the blocked flags (1 = floor, 2 = step / wall)

-==================

-*/

-#define	STOP_EPSILON	0.1

-

-int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)

-{

-	float	backoff;

-	float	change;

-	int		i, blocked;

-	

-	blocked = 0;

-	if (normal[2] > 0)

-		blocked |= 1;		// floor

-	if (!normal[2])

-		blocked |= 2;		// step

-	

-	backoff = DotProduct (in, normal) * overbounce;

-

-	for (i=0 ; i<3 ; i++)

-	{

-		change = normal[i]*backoff;

-		out[i] = in[i] - change;

-		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)

-			out[i] = 0;

-	}

-	

-	return blocked;

-}

-

-

-/*

-============

-SV_FlyMove

-

-The basic solid body movement clip that slides along multiple planes

-Returns the clipflags if the velocity was modified (hit something solid)

-1 = floor

-2 = wall / step

-4 = dead stop

-If steptrace is not NULL, the trace of any vertical wall hit will be stored

-============

-*/

-#define	MAX_CLIP_PLANES	5

-int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)

-{

-	int			bumpcount, numbumps;

-	vec3_t		dir;

-	float		d;

-	int			numplanes;

-	vec3_t		planes[MAX_CLIP_PLANES];

-	vec3_t		primal_velocity, original_velocity, new_velocity;

-	int			i, j;

-	trace_t		trace;

-	vec3_t		end;

-	float		time_left;

-	int			blocked;

-	

-	numbumps = 4;

-	

-	blocked = 0;

-	VectorCopy (ent->v.velocity, original_velocity);

-	VectorCopy (ent->v.velocity, primal_velocity);

-	numplanes = 0;

-	

-	time_left = time;

-

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

-	{

-		if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])

-			break;

-

-		for (i=0 ; i<3 ; i++)

-			end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];

-

-		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);

-

-		if (trace.allsolid)

-		{	// entity is trapped in another solid

-			VectorCopy (vec3_origin, ent->v.velocity);

-			return 3;

-		}

-

-		if (trace.fraction > 0)

-		{	// actually covered some distance

-			VectorCopy (trace.endpos, ent->v.origin);

-			VectorCopy (ent->v.velocity, original_velocity);

-			numplanes = 0;

-		}

-

-		if (trace.fraction == 1)

-			 break;		// moved the entire distance

-

-		if (!trace.ent)

-			Sys_Error ("SV_FlyMove: !trace.ent");

-

-		if (trace.plane.normal[2] > 0.7)

-		{

-			blocked |= 1;		// floor

-			if (trace.ent->v.solid == SOLID_BSP)

-			{

-				ent->v.flags =	(int)ent->v.flags | FL_ONGROUND;

-				ent->v.groundentity = EDICT_TO_PROG(trace.ent);

-			}

-		}

-		if (!trace.plane.normal[2])

-		{

-			blocked |= 2;		// step

-			if (steptrace)

-				*steptrace = trace;	// save for player extrafriction

-		}

-

-//

-// run the impact function

-//

-		SV_Impact (ent, trace.ent);

-		if (ent->free)

-			break;		// removed by the impact function

-

-		

-		time_left -= time_left * trace.fraction;

-		

-	// cliped to another plane

-		if (numplanes >= MAX_CLIP_PLANES)

-		{	// this shouldn't really happen

-			VectorCopy (vec3_origin, ent->v.velocity);

-			return 3;

-		}

-

-		VectorCopy (trace.plane.normal, planes[numplanes]);

-		numplanes++;

-

-//

-// modify original_velocity so it parallels all of the clip planes

-//

-		for (i=0 ; i<numplanes ; i++)

-		{

-			ClipVelocity (original_velocity, planes[i], new_velocity, 1);

-			for (j=0 ; j<numplanes ; j++)

-				if (j != i)

-				{

-					if (DotProduct (new_velocity, planes[j]) < 0)

-						break;	// not ok

-				}

-			if (j == numplanes)

-				break;

-		}

-		

-		if (i != numplanes)

-		{	// go along this plane

-			VectorCopy (new_velocity, ent->v.velocity);

-		}

-		else

-		{	// go along the crease

-			if (numplanes != 2)

-			{

-//				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);

-				VectorCopy (vec3_origin, ent->v.velocity);

-				return 7;

-			}

-			CrossProduct (planes[0], planes[1], dir);

-			d = DotProduct (dir, ent->v.velocity);

-			VectorScale (dir, d, ent->v.velocity);

-		}

-

-//

-// if original velocity is against the original velocity, stop dead

-// to avoid tiny occilations in sloping corners

-//

-		if (DotProduct (ent->v.velocity, primal_velocity) <= 0)

-		{

-			VectorCopy (vec3_origin, ent->v.velocity);

-			return blocked;

-		}

-	}

-

-	return blocked;

-}

-

-

-/*

-============

-SV_AddGravity

-

-============

-*/

-void SV_AddGravity (edict_t *ent)

-{

-	float	ent_gravity;

-

-#ifdef QUAKE2

-	if (ent->v.gravity)

-		ent_gravity = ent->v.gravity;

-	else

-		ent_gravity = 1.0;

-#else

-	eval_t	*val;

-

-	val = GetEdictFieldValue(ent, "gravity");

-	if (val && val->_float)

-		ent_gravity = val->_float;

-	else

-		ent_gravity = 1.0;

-#endif

-	ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;

-}

-

-

-/*

-===============================================================================

-

-PUSHMOVE

-

-===============================================================================

-*/

-

-/*

-============

-SV_PushEntity

-

-Does not change the entities velocity at all

-============

-*/

-trace_t SV_PushEntity (edict_t *ent, vec3_t push)

-{

-	trace_t	trace;

-	vec3_t	end;

-		

-	VectorAdd (ent->v.origin, push, end);

-

-	if (ent->v.movetype == MOVETYPE_FLYMISSILE)

-		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);

-	else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)

-	// only clip against bmodels

-		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);

-	else

-		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);	

-	

-	VectorCopy (trace.endpos, ent->v.origin);

-	SV_LinkEdict (ent, true);

-

-	if (trace.ent)

-		SV_Impact (ent, trace.ent);		

-

-	return trace;

-}					

-

-

-/*

-============

-SV_PushMove

-

-============

-*/

-void SV_PushMove (edict_t *pusher, float movetime)

-{

-	int			i, e;

-	edict_t		*check, *block;

-	vec3_t		mins, maxs, move;

-	vec3_t		entorig, pushorig;

-	int			num_moved;

-	edict_t		*moved_edict[MAX_EDICTS];

-	vec3_t		moved_from[MAX_EDICTS];

-

-	if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])

-	{

-		pusher->v.ltime += movetime;

-		return;

-	}

-

-	for (i=0 ; i<3 ; i++)

-	{

-		move[i] = pusher->v.velocity[i] * movetime;

-		mins[i] = pusher->v.absmin[i] + move[i];

-		maxs[i] = pusher->v.absmax[i] + move[i];

-	}

-

-	VectorCopy (pusher->v.origin, pushorig);

-	

-// move the pusher to it's final position

-

-	VectorAdd (pusher->v.origin, move, pusher->v.origin);

-	pusher->v.ltime += movetime;

-	SV_LinkEdict (pusher, false);

-

-

-// see if any solid entities are inside the final position

-	num_moved = 0;

-	check = NEXT_EDICT(sv.edicts);

-	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))

-	{

-		if (check->free)

-			continue;

-		if (check->v.movetype == MOVETYPE_PUSH

-		|| check->v.movetype == MOVETYPE_NONE

-#ifdef QUAKE2

-		|| check->v.movetype == MOVETYPE_FOLLOW

-#endif

-		|| check->v.movetype == MOVETYPE_NOCLIP)

-			continue;

-

-	// if the entity is standing on the pusher, it will definately be moved

-		if ( ! ( ((int)check->v.flags & FL_ONGROUND)

-		&& PROG_TO_EDICT(check->v.groundentity) == pusher) )

-		{

-			if ( check->v.absmin[0] >= maxs[0]

-			|| check->v.absmin[1] >= maxs[1]

-			|| check->v.absmin[2] >= maxs[2]

-			|| check->v.absmax[0] <= mins[0]

-			|| check->v.absmax[1] <= mins[1]

-			|| check->v.absmax[2] <= mins[2] )

-				continue;

-

-		// see if the ent's bbox is inside the pusher's final position

-			if (!SV_TestEntityPosition (check))

-				continue;

-		}

-

-	// remove the onground flag for non-players

-		if (check->v.movetype != MOVETYPE_WALK)

-			check->v.flags = (int)check->v.flags & ~FL_ONGROUND;

-		

-		VectorCopy (check->v.origin, entorig);

-		VectorCopy (check->v.origin, moved_from[num_moved]);

-		moved_edict[num_moved] = check;

-		num_moved++;

-

-		// try moving the contacted entity 

-		pusher->v.solid = SOLID_NOT;

-		SV_PushEntity (check, move);

-		pusher->v.solid = SOLID_BSP;

-

-	// if it is still inside the pusher, block

-		block = SV_TestEntityPosition (check);

-		if (block)

-		{	// fail the move

-			if (check->v.mins[0] == check->v.maxs[0])

-				continue;

-			if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)

-			{	// corpse

-				check->v.mins[0] = check->v.mins[1] = 0;

-				VectorCopy (check->v.mins, check->v.maxs);

-				continue;

-			}

-			

-			VectorCopy (entorig, check->v.origin);

-			SV_LinkEdict (check, true);

-

-			VectorCopy (pushorig, pusher->v.origin);

-			SV_LinkEdict (pusher, false);

-			pusher->v.ltime -= movetime;

-

-			// if the pusher has a "blocked" function, call it

-			// otherwise, just stay in place until the obstacle is gone

-			if (pusher->v.blocked)

-			{

-				pr_global_struct->self = EDICT_TO_PROG(pusher);

-				pr_global_struct->other = EDICT_TO_PROG(check);

-				PR_ExecuteProgram (pusher->v.blocked);

-			}

-			

-		// move back any entities we already moved

-			for (i=0 ; i<num_moved ; i++)

-			{

-				VectorCopy (moved_from[i], moved_edict[i]->v.origin);

-				SV_LinkEdict (moved_edict[i], false);

-			}

-			return;

-		}	

-	}

-

-	

-}

-

-#ifdef QUAKE2

-/*

-============

-SV_PushRotate

-

-============

-*/

-void SV_PushRotate (edict_t *pusher, float movetime)

-{

-	int			i, e;

-	edict_t		*check, *block;

-	vec3_t		move, a, amove;

-	vec3_t		entorig, pushorig;

-	int			num_moved;

-	edict_t		*moved_edict[MAX_EDICTS];

-	vec3_t		moved_from[MAX_EDICTS];

-	vec3_t		org, org2;

-	vec3_t		forward, right, up;

-

-	if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])

-	{

-		pusher->v.ltime += movetime;

-		return;

-	}

-

-	for (i=0 ; i<3 ; i++)

-		amove[i] = pusher->v.avelocity[i] * movetime;

-

-	VectorSubtract (vec3_origin, amove, a);

-	AngleVectors (a, forward, right, up);

-

-	VectorCopy (pusher->v.angles, pushorig);

-	

-// move the pusher to it's final position

-

-	VectorAdd (pusher->v.angles, amove, pusher->v.angles);

-	pusher->v.ltime += movetime;

-	SV_LinkEdict (pusher, false);

-

-

-// see if any solid entities are inside the final position

-	num_moved = 0;

-	check = NEXT_EDICT(sv.edicts);

-	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))

-	{

-		if (check->free)

-			continue;

-		if (check->v.movetype == MOVETYPE_PUSH

-		|| check->v.movetype == MOVETYPE_NONE

-		|| check->v.movetype == MOVETYPE_FOLLOW

-		|| check->v.movetype == MOVETYPE_NOCLIP)

-			continue;

-

-	// if the entity is standing on the pusher, it will definately be moved

-		if ( ! ( ((int)check->v.flags & FL_ONGROUND)

-		&& PROG_TO_EDICT(check->v.groundentity) == pusher) )

-		{

-			if ( check->v.absmin[0] >= pusher->v.absmax[0]

-			|| check->v.absmin[1] >= pusher->v.absmax[1]

-			|| check->v.absmin[2] >= pusher->v.absmax[2]

-			|| check->v.absmax[0] <= pusher->v.absmin[0]

-			|| check->v.absmax[1] <= pusher->v.absmin[1]

-			|| check->v.absmax[2] <= pusher->v.absmin[2] )

-				continue;

-

-		// see if the ent's bbox is inside the pusher's final position

-			if (!SV_TestEntityPosition (check))

-				continue;

-		}

-

-	// remove the onground flag for non-players

-		if (check->v.movetype != MOVETYPE_WALK)

-			check->v.flags = (int)check->v.flags & ~FL_ONGROUND;

-		

-		VectorCopy (check->v.origin, entorig);

-		VectorCopy (check->v.origin, moved_from[num_moved]);

-		moved_edict[num_moved] = check;

-		num_moved++;

-

-		// calculate destination position

-		VectorSubtract (check->v.origin, pusher->v.origin, org);

-		org2[0] = DotProduct (org, forward);

-		org2[1] = -DotProduct (org, right);

-		org2[2] = DotProduct (org, up);

-		VectorSubtract (org2, org, move);

-

-		// try moving the contacted entity 

-		pusher->v.solid = SOLID_NOT;

-		SV_PushEntity (check, move);

-		pusher->v.solid = SOLID_BSP;

-

-	// if it is still inside the pusher, block

-		block = SV_TestEntityPosition (check);

-		if (block)

-		{	// fail the move

-			if (check->v.mins[0] == check->v.maxs[0])

-				continue;

-			if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)

-			{	// corpse

-				check->v.mins[0] = check->v.mins[1] = 0;

-				VectorCopy (check->v.mins, check->v.maxs);

-				continue;

-			}

-			

-			VectorCopy (entorig, check->v.origin);

-			SV_LinkEdict (check, true);

-

-			VectorCopy (pushorig, pusher->v.angles);

-			SV_LinkEdict (pusher, false);

-			pusher->v.ltime -= movetime;

-

-			// if the pusher has a "blocked" function, call it

-			// otherwise, just stay in place until the obstacle is gone

-			if (pusher->v.blocked)

-			{

-				pr_global_struct->self = EDICT_TO_PROG(pusher);

-				pr_global_struct->other = EDICT_TO_PROG(check);

-				PR_ExecuteProgram (pusher->v.blocked);

-			}

-			

-		// move back any entities we already moved

-			for (i=0 ; i<num_moved ; i++)

-			{

-				VectorCopy (moved_from[i], moved_edict[i]->v.origin);

-				VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);

-				SV_LinkEdict (moved_edict[i], false);

-			}

-			return;

-		}

-		else

-		{

-			VectorAdd (check->v.angles, amove, check->v.angles);

-		}

-	}

-

-	

-}

-#endif

-

-/*

-================

-SV_Physics_Pusher

-

-================

-*/

-void SV_Physics_Pusher (edict_t *ent)

-{

-	float	thinktime;

-	float	oldltime;

-	float	movetime;

-

-	oldltime = ent->v.ltime;

-	

-	thinktime = ent->v.nextthink;

-	if (thinktime < ent->v.ltime + host_frametime)

-	{

-		movetime = thinktime - ent->v.ltime;

-		if (movetime < 0)

-			movetime = 0;

-	}

-	else

-		movetime = host_frametime;

-

-	if (movetime)

-	{

-#ifdef QUAKE2

-		if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])

-			SV_PushRotate (ent, movetime);

-		else

-#endif

-			SV_PushMove (ent, movetime);	// advances ent->v.ltime if not blocked

-	}

-		

-	if (thinktime > oldltime && thinktime <= ent->v.ltime)

-	{

-		ent->v.nextthink = 0;

-		pr_global_struct->time = sv.time;

-		pr_global_struct->self = EDICT_TO_PROG(ent);

-		pr_global_struct->other = EDICT_TO_PROG(sv.edicts);

-		PR_ExecuteProgram (ent->v.think);

-		if (ent->free)

-			return;

-	}

-

-}

-

-

-/*

-===============================================================================

-

-CLIENT MOVEMENT

-

-===============================================================================

-*/

-

-/*

-=============

-SV_CheckStuck

-

-This is a big hack to try and fix the rare case of getting stuck in the world

-clipping hull.

-=============

-*/

-void SV_CheckStuck (edict_t *ent)

-{

-	int		i, j;

-	int		z;

-	vec3_t	org;

-

-	if (!SV_TestEntityPosition(ent))

-	{

-		VectorCopy (ent->v.origin, ent->v.oldorigin);

-		return;

-	}

-

-	VectorCopy (ent->v.origin, org);

-	VectorCopy (ent->v.oldorigin, ent->v.origin);

-	if (!SV_TestEntityPosition(ent))

-	{

-		Con_DPrintf ("Unstuck.\n");

-		SV_LinkEdict (ent, true);

-		return;

-	}

-	

-	for (z=0 ; z< 18 ; z++)

-		for (i=-1 ; i <= 1 ; i++)

-			for (j=-1 ; j <= 1 ; j++)

-			{

-				ent->v.origin[0] = org[0] + i;

-				ent->v.origin[1] = org[1] + j;

-				ent->v.origin[2] = org[2] + z;

-				if (!SV_TestEntityPosition(ent))

-				{

-					Con_DPrintf ("Unstuck.\n");

-					SV_LinkEdict (ent, true);

-					return;

-				}

-			}

-			

-	VectorCopy (org, ent->v.origin);

-	Con_DPrintf ("player is stuck.\n");

-}

-

-

-/*

-=============

-SV_CheckWater

-=============

-*/

-qboolean SV_CheckWater (edict_t *ent)

-{

-	vec3_t	point;

-	int		cont;

-#ifdef QUAKE2

-	int		truecont;

-#endif

-

-	point[0] = ent->v.origin[0];

-	point[1] = ent->v.origin[1];

-	point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;	

-	

-	ent->v.waterlevel = 0;

-	ent->v.watertype = CONTENTS_EMPTY;

-	cont = SV_PointContents (point);

-	if (cont <= CONTENTS_WATER)

-	{

-#ifdef QUAKE2

-		truecont = SV_TruePointContents (point);

-#endif

-		ent->v.watertype = cont;

-		ent->v.waterlevel = 1;

-		point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;

-		cont = SV_PointContents (point);

-		if (cont <= CONTENTS_WATER)

-		{

-			ent->v.waterlevel = 2;

-			point[2] = ent->v.origin[2] + ent->v.view_ofs[2];

-			cont = SV_PointContents (point);

-			if (cont <= CONTENTS_WATER)

-				ent->v.waterlevel = 3;

-		}

-#ifdef QUAKE2

-		if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)

-		{

-			static vec3_t current_table[] =

-			{

-				{1, 0, 0},

-				{0, 1, 0},

-				{-1, 0, 0},

-				{0, -1, 0},

-				{0, 0, 1},

-				{0, 0, -1}

-			};

-

-			VectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity);

-		}

-#endif

-	}

-	

-	return ent->v.waterlevel > 1;

-}

-

-/*

-============

-SV_WallFriction

-

-============

-*/

-void SV_WallFriction (edict_t *ent, trace_t *trace)

-{

-	vec3_t		forward, right, up;

-	float		d, i;

-	vec3_t		into, side;

-	

-	AngleVectors (ent->v.v_angle, forward, right, up);

-	d = DotProduct (trace->plane.normal, forward);

-	

-	d += 0.5;

-	if (d >= 0)

-		return;

-		

-// cut the tangential velocity

-	i = DotProduct (trace->plane.normal, ent->v.velocity);

-	VectorScale (trace->plane.normal, i, into);

-	VectorSubtract (ent->v.velocity, into, side);

-	

-	ent->v.velocity[0] = side[0] * (1 + d);

-	ent->v.velocity[1] = side[1] * (1 + d);

-}

-

-/*

-=====================

-SV_TryUnstick

-

-Player has come to a dead stop, possibly due to the problem with limited

-float precision at some angle joins in the BSP hull.

-

-Try fixing by pushing one pixel in each direction.

-

-This is a hack, but in the interest of good gameplay...

-======================

-*/

-int SV_TryUnstick (edict_t *ent, vec3_t oldvel)

-{

-	int		i;

-	vec3_t	oldorg;

-	vec3_t	dir;

-	int		clip;

-	trace_t	steptrace;

-	

-	VectorCopy (ent->v.origin, oldorg);

-	VectorCopy (vec3_origin, dir);

-

-	for (i=0 ; i<8 ; i++)

-	{

-// try pushing a little in an axial direction

-		switch (i)

-		{

-			case 0:	dir[0] = 2; dir[1] = 0; break;

-			case 1:	dir[0] = 0; dir[1] = 2; break;

-			case 2:	dir[0] = -2; dir[1] = 0; break;

-			case 3:	dir[0] = 0; dir[1] = -2; break;

-			case 4:	dir[0] = 2; dir[1] = 2; break;

-			case 5:	dir[0] = -2; dir[1] = 2; break;

-			case 6:	dir[0] = 2; dir[1] = -2; break;

-			case 7:	dir[0] = -2; dir[1] = -2; break;

-		}

-		

-		SV_PushEntity (ent, dir);

-

-// retry the original move

-		ent->v.velocity[0] = oldvel[0];

-		ent->v. velocity[1] = oldvel[1];

-		ent->v. velocity[2] = 0;

-		clip = SV_FlyMove (ent, 0.1, &steptrace);

-

-		if ( fabs(oldorg[1] - ent->v.origin[1]) > 4

-		|| fabs(oldorg[0] - ent->v.origin[0]) > 4 )

-		{

-//Con_DPrintf ("unstuck!\n");

-			return clip;

-		}

-			

-// go back to the original pos and try again

-		VectorCopy (oldorg, ent->v.origin);

-	}

-	

-	VectorCopy (vec3_origin, ent->v.velocity);

-	return 7;		// still not moving

-}

-

-/*

-=====================

-SV_WalkMove

-

-Only used by players

-======================

-*/

-#define	STEPSIZE	18

-void SV_WalkMove (edict_t *ent)

-{

-	vec3_t		upmove, downmove;

-	vec3_t		oldorg, oldvel;

-	vec3_t		nosteporg, nostepvel;

-	int			clip;

-	int			oldonground;

-	trace_t		steptrace, downtrace;

-	

-//

-// do a regular slide move unless it looks like you ran into a step

-//

-	oldonground = (int)ent->v.flags & FL_ONGROUND;

-	ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;

-	

-	VectorCopy (ent->v.origin, oldorg);

-	VectorCopy (ent->v.velocity, oldvel);

-	

-	clip = SV_FlyMove (ent, host_frametime, &steptrace);

-

-	if ( !(clip & 2) )

-		return;		// move didn't block on a step

-

-	if (!oldonground && ent->v.waterlevel == 0)

-		return;		// don't stair up while jumping

-	

-	if (ent->v.movetype != MOVETYPE_WALK)

-		return;		// gibbed by a trigger

-	

-	if (sv_nostep.value)

-		return;

-	

-	if ( (int)sv_player->v.flags & FL_WATERJUMP )

-		return;

-

-	VectorCopy (ent->v.origin, nosteporg);

-	VectorCopy (ent->v.velocity, nostepvel);

-

-//

-// try moving up and forward to go up a step

-//

-	VectorCopy (oldorg, ent->v.origin);	// back to start pos

-

-	VectorCopy (vec3_origin, upmove);

-	VectorCopy (vec3_origin, downmove);

-	upmove[2] = STEPSIZE;

-	downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;

-

-// move up

-	SV_PushEntity (ent, upmove);	// FIXME: don't link?

-

-// move forward

-	ent->v.velocity[0] = oldvel[0];

-	ent->v. velocity[1] = oldvel[1];

-	ent->v. velocity[2] = 0;

-	clip = SV_FlyMove (ent, host_frametime, &steptrace);

-

-// check for stuckness, possibly due to the limited precision of floats

-// in the clipping hulls

-	if (clip)

-	{

-		if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125

-		&& fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )

-		{	// stepping up didn't make any progress

-			clip = SV_TryUnstick (ent, oldvel);

-		}

-	}

-	

-// extra friction based on view angle

-	if ( clip & 2 )

-		SV_WallFriction (ent, &steptrace);

-

-// move down

-	downtrace = SV_PushEntity (ent, downmove);	// FIXME: don't link?

-

-	if (downtrace.plane.normal[2] > 0.7)

-	{

-		if (ent->v.solid == SOLID_BSP)

-		{

-			ent->v.flags =	(int)ent->v.flags | FL_ONGROUND;

-			ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);

-		}

-	}

-	else

-	{

-// if the push down didn't end up on good ground, use the move without

-// the step up.  This happens near wall / slope combinations, and can

-// cause the player to hop up higher on a slope too steep to climb	

-		VectorCopy (nosteporg, ent->v.origin);

-		VectorCopy (nostepvel, ent->v.velocity);

-	}

-}

-

-

-/*

-================

-SV_Physics_Client

-

-Player character actions

-================

-*/

-void SV_Physics_Client (edict_t	*ent, int num)

-{

-	if ( ! svs.clients[num-1].active )

-		return;		// unconnected slot

-

-//

-// call standard client pre-think

-//	

-	pr_global_struct->time = sv.time;

-	pr_global_struct->self = EDICT_TO_PROG(ent);

-	PR_ExecuteProgram (pr_global_struct->PlayerPreThink);

-	

-//

-// do a move

-//

-	SV_CheckVelocity (ent);

-

-//

-// decide which move function to call

-//

-	switch ((int)ent->v.movetype)

-	{

-	case MOVETYPE_NONE:

-		if (!SV_RunThink (ent))

-			return;

-		break;

-

-	case MOVETYPE_WALK:

-		if (!SV_RunThink (ent))

-			return;

-		if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )

-			SV_AddGravity (ent);

-		SV_CheckStuck (ent);

-#ifdef QUAKE2

-		VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);

-#endif

-		SV_WalkMove (ent);

-

-#ifdef QUAKE2

-		VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);

-#endif

-		break;

-		

-	case MOVETYPE_TOSS:

-	case MOVETYPE_BOUNCE:

-		SV_Physics_Toss (ent);

-		break;

-

-	case MOVETYPE_FLY:

-		if (!SV_RunThink (ent))

-			return;

-		SV_FlyMove (ent, host_frametime, NULL);

-		break;

-		

-	case MOVETYPE_NOCLIP:

-		if (!SV_RunThink (ent))

-			return;

-		VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);

-		break;

-		

-	default:

-		Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);

-	}

-

-//

-// call standard player post-think

-//		

-	SV_LinkEdict (ent, true);

-

-	pr_global_struct->time = sv.time;

-	pr_global_struct->self = EDICT_TO_PROG(ent);

-	PR_ExecuteProgram (pr_global_struct->PlayerPostThink);

-}

-

-//============================================================================

-

-/*

-=============

-SV_Physics_None

-

-Non moving objects can only think

-=============

-*/

-void SV_Physics_None (edict_t *ent)

-{

-// regular thinking

-	SV_RunThink (ent);

-}

-

-#ifdef QUAKE2

-/*

-=============

-SV_Physics_Follow

-

-Entities that are "stuck" to another entity

-=============

-*/

-void SV_Physics_Follow (edict_t *ent)

-{

-// regular thinking

-	SV_RunThink (ent);

-	VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);

-	SV_LinkEdict (ent, true);

-}

-#endif

-

-/*

-=============

-SV_Physics_Noclip

-

-A moving object that doesn't obey physics

-=============

-*/

-void SV_Physics_Noclip (edict_t *ent)

-{

-// regular thinking

-	if (!SV_RunThink (ent))

-		return;

-	

-	VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);

-	VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);

-

-	SV_LinkEdict (ent, false);

-}

-

-/*

-==============================================================================

-

-TOSS / BOUNCE

-

-==============================================================================

-*/

-

-/*

-=============

-SV_CheckWaterTransition

-

-=============

-*/

-void SV_CheckWaterTransition (edict_t *ent)

-{

-	int		cont;

-#ifdef QUAKE2

-	vec3_t	point;

-	

-	point[0] = ent->v.origin[0];

-	point[1] = ent->v.origin[1];

-	point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;	

-	cont = SV_PointContents (point);

-#else

-	cont = SV_PointContents (ent->v.origin);

-#endif

-	if (!ent->v.watertype)

-	{	// just spawned here

-		ent->v.watertype = cont;

-		ent->v.waterlevel = 1;

-		return;

-	}

-	

-	if (cont <= CONTENTS_WATER)

-	{

-		if (ent->v.watertype == CONTENTS_EMPTY)

-		{	// just crossed into water

-			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);

-		}		

-		ent->v.watertype = cont;

-		ent->v.waterlevel = 1;

-	}

-	else

-	{

-		if (ent->v.watertype != CONTENTS_EMPTY)

-		{	// just crossed into water

-			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);

-		}		

-		ent->v.watertype = CONTENTS_EMPTY;

-		ent->v.waterlevel = cont;

-	}

-}

-

-/*

-=============

-SV_Physics_Toss

-

-Toss, bounce, and fly movement.  When onground, do nothing.

-=============

-*/

-void SV_Physics_Toss (edict_t *ent)

-{

-	trace_t	trace;

-	vec3_t	move;

-	float	backoff;

-#ifdef QUAKE2

-	edict_t	*groundentity;

-

-	groundentity = PROG_TO_EDICT(ent->v.groundentity);

-	if ((int)groundentity->v.flags & FL_CONVEYOR)

-		VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);

-	else

-		VectorCopy(vec_origin, ent->v.basevelocity);

-	SV_CheckWater (ent);

-#endif

-	// regular thinking

-	if (!SV_RunThink (ent))

-		return;

-

-#ifdef QUAKE2

-	if (ent->v.velocity[2] > 0)

-		ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;

-

-	if ( ((int)ent->v.flags & FL_ONGROUND) )

-//@@

-		if (VectorCompare(ent->v.basevelocity, vec_origin))

-			return;

-

-	SV_CheckVelocity (ent);

-

-// add gravity

-	if (! ((int)ent->v.flags & FL_ONGROUND)

-		&& ent->v.movetype != MOVETYPE_FLY

-		&& ent->v.movetype != MOVETYPE_BOUNCEMISSILE

-		&& ent->v.movetype != MOVETYPE_FLYMISSILE)

-			SV_AddGravity (ent);

-

-#else

-// if onground, return without moving

-	if ( ((int)ent->v.flags & FL_ONGROUND) )

-		return;

-

-	SV_CheckVelocity (ent);

-

-// add gravity

-	if (ent->v.movetype != MOVETYPE_FLY

-	&& ent->v.movetype != MOVETYPE_FLYMISSILE)

-		SV_AddGravity (ent);

-#endif

-

-// move angles

-	VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);

-

-// move origin

-#ifdef QUAKE2

-	VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);

-#endif

-	VectorScale (ent->v.velocity, host_frametime, move);

-	trace = SV_PushEntity (ent, move);

-#ifdef QUAKE2

-	VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);

-#endif

-	if (trace.fraction == 1)

-		return;

-	if (ent->free)

-		return;

-	

-	if (ent->v.movetype == MOVETYPE_BOUNCE)

-		backoff = 1.5;

-#ifdef QUAKE2

-	else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)

-		backoff = 2.0;

-#endif

-	else

-		backoff = 1;

-

-	ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);

-

-// stop if on ground

-	if (trace.plane.normal[2] > 0.7)

-	{		

-#ifdef QUAKE2

-		if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))

-#else

-		if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE)

-#endif

-		{

-			ent->v.flags = (int)ent->v.flags | FL_ONGROUND;

-			ent->v.groundentity = EDICT_TO_PROG(trace.ent);

-			VectorCopy (vec3_origin, ent->v.velocity);

-			VectorCopy (vec3_origin, ent->v.avelocity);

-		}

-	}

-	

-// check for in water

-	SV_CheckWaterTransition (ent);

-}

-

-/*

-===============================================================================

-

-STEPPING MOVEMENT

-

-===============================================================================

-*/

-

-/*

-=============

-SV_Physics_Step

-

-Monsters freefall when they don't have a ground entity, otherwise

-all movement is done with discrete steps.

-

-This is also used for objects that have become still on the ground, but

-will fall if the floor is pulled out from under them.

-=============

-*/

-#ifdef QUAKE2

-void SV_Physics_Step (edict_t *ent)

-{

-	qboolean	wasonground;

-	qboolean	inwater;

-	qboolean	hitsound = false;

-	float		*vel;

-	float		speed, newspeed, control;

-	float		friction;

-	edict_t		*groundentity;

-

-	groundentity = PROG_TO_EDICT(ent->v.groundentity);

-	if ((int)groundentity->v.flags & FL_CONVEYOR)

-		VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);

-	else

-		VectorCopy(vec_origin, ent->v.basevelocity);

-//@@

-	pr_global_struct->time = sv.time;

-	pr_global_struct->self = EDICT_TO_PROG(ent);

-	PF_WaterMove();

-

-	SV_CheckVelocity (ent);

-

-	wasonground = (int)ent->v.flags & FL_ONGROUND;

-//	ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;

-

-	// add gravity except:

-	//   flying monsters

-	//   swimming monsters who are in the water

-	inwater = SV_CheckWater(ent);

-	if (! wasonground)

-		if (!((int)ent->v.flags & FL_FLY))

-			if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0)))

-			{

-				if (ent->v.velocity[2] < sv_gravity.value*-0.1)

-					hitsound = true;

-				if (!inwater)

-					SV_AddGravity (ent);

-			}

-

-	if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin))

-	{

-		ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;

-		// apply friction

-		// let dead monsters who aren't completely onground slide

-		if (wasonground)

-			if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent)))

-			{

-				vel = ent->v.velocity;

-				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);

-				if (speed)

-				{

-					friction = sv_friction.value;

-

-					control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;

-					newspeed = speed - host_frametime*control*friction;

-

-					if (newspeed < 0)

-						newspeed = 0;

-					newspeed /= speed;

-

-					vel[0] = vel[0] * newspeed;

-					vel[1] = vel[1] * newspeed;

-				}

-			}

-

-		VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);

-		SV_FlyMove (ent, host_frametime, NULL);

-		VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);

-

-		// determine if it's on solid ground at all

-		{

-			vec3_t	mins, maxs, point;

-			int		x, y;

-		

-			VectorAdd (ent->v.origin, ent->v.mins, mins);

-			VectorAdd (ent->v.origin, ent->v.maxs, maxs);

-

-			point[2] = mins[2] - 1;

-			for	(x=0 ; x<=1 ; x++)

-				for	(y=0 ; y<=1 ; y++)

-				{

-					point[0] = x ? maxs[0] : mins[0];

-					point[1] = y ? maxs[1] : mins[1];

-					if (SV_PointContents (point) == CONTENTS_SOLID)

-					{

-						ent->v.flags = (int)ent->v.flags | FL_ONGROUND;

-						break;

-					}

-				}

-

-		}

-

-		SV_LinkEdict (ent, true);

-

-		if ((int)ent->v.flags & FL_ONGROUND)

-			if (!wasonground)

-				if (hitsound)

-					SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);

-	}

-

-// regular thinking

-	SV_RunThink (ent);

-	SV_CheckWaterTransition (ent);

-}

-#else

-void SV_Physics_Step (edict_t *ent)

-{

-	qboolean	hitsound;

-

-// freefall if not onground

-	if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )

-	{

-		if (ent->v.velocity[2] < sv_gravity.value*-0.1)

-			hitsound = true;

-		else

-			hitsound = false;

-

-		SV_AddGravity (ent);

-		SV_CheckVelocity (ent);

-		SV_FlyMove (ent, host_frametime, NULL);

-		SV_LinkEdict (ent, true);

-

-		if ( (int)ent->v.flags & FL_ONGROUND )	// just hit ground

-		{

-			if (hitsound)

-				SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);

-		}

-	}

-

-// regular thinking

-	SV_RunThink (ent);

-	

-	SV_CheckWaterTransition (ent);

-}

-#endif

-

-//============================================================================

-

-/*

-================

-SV_Physics

-

-================

-*/

-void SV_Physics (void)

-{

-	int		i;

-	edict_t	*ent;

-

-// let the progs know that a new frame has started

-	pr_global_struct->self = EDICT_TO_PROG(sv.edicts);

-	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);

-	pr_global_struct->time = sv.time;

-	PR_ExecuteProgram (pr_global_struct->StartFrame);

-

-//SV_CheckAllEnts ();

-

-//

-// treat each object in turn

-//

-	ent = sv.edicts;

-	for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))

-	{

-		if (ent->free)

-			continue;

-

-		if (pr_global_struct->force_retouch)

-		{

-			SV_LinkEdict (ent, true);	// force retouch even for stationary

-		}

-

-		if (i > 0 && i <= svs.maxclients)

-			SV_Physics_Client (ent, i);

-		else if (ent->v.movetype == MOVETYPE_PUSH)

-			SV_Physics_Pusher (ent);

-		else if (ent->v.movetype == MOVETYPE_NONE)

-			SV_Physics_None (ent);

-#ifdef QUAKE2

-		else if (ent->v.movetype == MOVETYPE_FOLLOW)

-			SV_Physics_Follow (ent);

-#endif

-		else if (ent->v.movetype == MOVETYPE_NOCLIP)

-			SV_Physics_Noclip (ent);

-		else if (ent->v.movetype == MOVETYPE_STEP)

-			SV_Physics_Step (ent);

-		else if (ent->v.movetype == MOVETYPE_TOSS 

-		|| ent->v.movetype == MOVETYPE_BOUNCE

-#ifdef QUAKE2

-		|| ent->v.movetype == MOVETYPE_BOUNCEMISSILE

-#endif

-		|| ent->v.movetype == MOVETYPE_FLY

-		|| ent->v.movetype == MOVETYPE_FLYMISSILE)

-			SV_Physics_Toss (ent);

-		else

-			Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);			

-	}

-	

-	if (pr_global_struct->force_retouch)

-		pr_global_struct->force_retouch--;	

-

-	sv.time += host_frametime;

-}

-

-

-#ifdef QUAKE2

-trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)

-{

-	edict_t	tempent, *tent;

-	trace_t	trace;

-	vec3_t	move;

-	vec3_t	end;

-	double	save_frametime;

-//	extern particle_t	*active_particles, *free_particles;

-//	particle_t	*p;

-

-

-	save_frametime = host_frametime;

-	host_frametime = 0.05;

-

-	memcpy(&tempent, ent, sizeof(edict_t));

-	tent = &tempent;

-

-	while (1)

-	{

-		SV_CheckVelocity (tent);

-		SV_AddGravity (tent);

-		VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);

-		VectorScale (tent->v.velocity, host_frametime, move);

-		VectorAdd (tent->v.origin, move, end);

-		trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);	

-		VectorCopy (trace.endpos, tent->v.origin);

-

-//		p = free_particles;

-//		if (p)

-//		{

-//			free_particles = p->next;

-//			p->next = active_particles;

-//			active_particles = p;

-//		

-//			p->die = 256;

-//			p->color = 15;

-//			p->type = pt_static;

-//			VectorCopy (vec3_origin, p->vel);

-//			VectorCopy (tent->v.origin, p->org);

-//		}

-

-		if (trace.ent)

-			if (trace.ent != ignore)

-				break;

-	}

-//	p->color = 224;

-	host_frametime = save_frametime;

-	return trace;

-}

-#endif

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// sv_phys.c
+
+#include "quakedef.h"
+
+/*
+
+
+pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
+
+onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects 
+
+doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
+bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
+corpses are SOLID_NOT and MOVETYPE_TOSS
+crates are SOLID_BBOX and MOVETYPE_TOSS
+walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
+flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
+
+solid_edge items only clip against bsp models.
+
+*/
+
+cvar_t	sv_friction = CVAR4("sv_friction","4",false,true);
+cvar_t	sv_stopspeed = CVAR2("sv_stopspeed","100");
+cvar_t	sv_gravity = CVAR4("sv_gravity","800",false,true);
+cvar_t	sv_maxvelocity = CVAR2("sv_maxvelocity","2000");
+cvar_t	sv_nostep = CVAR2("sv_nostep","0");
+
+#ifdef QUAKE2
+static	vec3_t	vec_origin = {0.0, 0.0, 0.0};
+#endif
+
+#define	MOVE_EPSILON	0.01
+
+void SV_Physics_Toss (edict_t *ent);
+
+/*
+================
+SV_CheckAllEnts
+================
+*/
+void SV_CheckAllEnts (void)
+{
+	int			e;
+	edict_t		*check;
+
+// see if any solid entities are inside the final position
+	check = NEXT_EDICT(sv.edicts);
+	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
+	{
+		if (check->free)
+			continue;
+		if (check->u.v.movetype == MOVETYPE_PUSH
+		|| check->u.v.movetype == MOVETYPE_NONE
+#ifdef QUAKE2
+		|| check->u.v.movetype == MOVETYPE_FOLLOW
+#endif
+		|| check->u.v.movetype == MOVETYPE_NOCLIP)
+			continue;
+
+		if (SV_TestEntityPosition (check))
+			Con_Printf ("entity in invalid position\n");
+	}
+}
+
+/*
+================
+SV_CheckVelocity
+================
+*/
+void SV_CheckVelocity (edict_t *ent)
+{
+	int		i;
+
+//
+// bound velocity
+//
+	for (i=0 ; i<3 ; i++)
+	{
+		if (IS_NAN(ent->u.v.velocity[i]))
+		{
+			Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->u.v.classname);
+			ent->u.v.velocity[i] = 0;
+		}
+		if (IS_NAN(ent->u.v.origin[i]))
+		{
+			Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->u.v.classname);
+			ent->u.v.origin[i] = 0;
+		}
+		if (ent->u.v.velocity[i] > sv_maxvelocity.value)
+			ent->u.v.velocity[i] = sv_maxvelocity.value;
+		else if (ent->u.v.velocity[i] < -sv_maxvelocity.value)
+			ent->u.v.velocity[i] = -sv_maxvelocity.value;
+	}
+}
+
+/*
+=============
+SV_RunThink
+
+Runs thinking code if time.  There is some play in the exact time the think
+function will be called, because it is called before any movement is done
+in a frame.  Not used for pushmove objects, because they must be exact.
+Returns false if the entity removed itself.
+=============
+*/
+qboolean SV_RunThink (edict_t *ent)
+{
+	float	thinktime;
+
+	thinktime = ent->u.v.nextthink;
+	if (thinktime <= 0 || thinktime > sv.time + host_frametime)
+		return true;
+		
+	if (thinktime < sv.time)
+		thinktime = sv.time;	// don't let things stay in the past.
+								// it is possible to start that way
+								// by a trigger with a local time.
+	ent->u.v.nextthink = 0;
+	pr_global_struct->time = thinktime;
+	pr_global_struct->self = EDICT_TO_PROG(ent);
+	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
+	PR_ExecuteProgram (ent->u.v.think);
+	return !ent->free;
+}
+
+/*
+==================
+SV_Impact
+
+Two entities have touched, so run their touch functions
+==================
+*/
+void SV_Impact (edict_t *e1, edict_t *e2)
+{
+	int		old_self, old_other;
+	
+	old_self = pr_global_struct->self;
+	old_other = pr_global_struct->other;
+	
+	pr_global_struct->time = sv.time;
+	if (e1->u.v.touch && e1->u.v.solid != SOLID_NOT)
+	{
+		pr_global_struct->self = EDICT_TO_PROG(e1);
+		pr_global_struct->other = EDICT_TO_PROG(e2);
+		PR_ExecuteProgram (e1->u.v.touch);
+	}
+	
+	if (e2->u.v.touch && e2->u.v.solid != SOLID_NOT)
+	{
+		pr_global_struct->self = EDICT_TO_PROG(e2);
+		pr_global_struct->other = EDICT_TO_PROG(e1);
+		PR_ExecuteProgram (e2->u.v.touch);
+	}
+
+	pr_global_struct->self = old_self;
+	pr_global_struct->other = old_other;
+}
+
+
+/*
+==================
+ClipVelocity
+
+Slide off of the impacting object
+returns the blocked flags (1 = floor, 2 = step / wall)
+==================
+*/
+#define	STOP_EPSILON	0.1
+
+int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+{
+	float	backoff;
+	float	change;
+	int		i, blocked;
+	
+	blocked = 0;
+	if (normal[2] > 0)
+		blocked |= 1;		// floor
+	if (!normal[2])
+		blocked |= 2;		// step
+	
+	backoff = DotProduct (in, normal) * overbounce;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		change = normal[i]*backoff;
+		out[i] = in[i] - change;
+		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
+			out[i] = 0;
+	}
+	
+	return blocked;
+}
+
+
+/*
+============
+SV_FlyMove
+
+The basic solid body movement clip that slides along multiple planes
+Returns the clipflags if the velocity was modified (hit something solid)
+1 = floor
+2 = wall / step
+4 = dead stop
+If steptrace is not NULL, the trace of any vertical wall hit will be stored
+============
+*/
+#define	MAX_CLIP_PLANES	5
+int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
+{
+	int			bumpcount, numbumps;
+	vec3_t		dir;
+	float		d;
+	int			numplanes;
+	vec3_t		planes[MAX_CLIP_PLANES];
+	vec3_t		primal_velocity, original_velocity, new_velocity;
+	int			i, j;
+	trace_t		trace;
+	vec3_t		end;
+	float		time_left;
+	int			blocked;
+	
+	numbumps = 4;
+	
+	blocked = 0;
+	VectorCopy (ent->u.v.velocity, original_velocity);
+	VectorCopy (ent->u.v.velocity, primal_velocity);
+	numplanes = 0;
+	
+	time_left = time;
+
+	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+	{
+		if (!ent->u.v.velocity[0] && !ent->u.v.velocity[1] && !ent->u.v.velocity[2])
+			break;
+
+		for (i=0 ; i<3 ; i++)
+			end[i] = ent->u.v.origin[i] + time_left * ent->u.v.velocity[i];
+
+		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
+
+		if (trace.allsolid)
+		{	// entity is trapped in another solid
+			VectorCopy (vec3_origin, ent->u.v.velocity);
+			return 3;
+		}
+
+		if (trace.fraction > 0)
+		{	// actually covered some distance
+			VectorCopy (trace.endpos, ent->u.v.origin);
+			VectorCopy (ent->u.v.velocity, original_velocity);
+			numplanes = 0;
+		}
+
+		if (trace.fraction == 1)
+			 break;		// moved the entire distance
+
+		if (!trace.ent)
+			Sys_Error ("SV_FlyMove: !trace.ent");
+
+		if (trace.plane.normal[2] > 0.7)
+		{
+			blocked |= 1;		// floor
+			if (trace.ent->u.v.solid == SOLID_BSP)
+			{
+				ent->u.v.flags =	(int)ent->u.v.flags | FL_ONGROUND;
+				ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
+			}
+		}
+		if (!trace.plane.normal[2])
+		{
+			blocked |= 2;		// step
+			if (steptrace)
+				*steptrace = trace;	// save for player extrafriction
+		}
+
+//
+// run the impact function
+//
+		SV_Impact (ent, trace.ent);
+		if (ent->free)
+			break;		// removed by the impact function
+
+		
+		time_left -= time_left * trace.fraction;
+		
+	// cliped to another plane
+		if (numplanes >= MAX_CLIP_PLANES)
+		{	// this shouldn't really happen
+			VectorCopy (vec3_origin, ent->u.v.velocity);
+			return 3;
+		}
+
+		VectorCopy (trace.plane.normal, planes[numplanes]);
+		numplanes++;
+
+//
+// modify original_velocity so it parallels all of the clip planes
+//
+		for (i=0 ; i<numplanes ; i++)
+		{
+			ClipVelocity (original_velocity, planes[i], new_velocity, 1);
+			for (j=0 ; j<numplanes ; j++)
+				if (j != i)
+				{
+					if (DotProduct (new_velocity, planes[j]) < 0)
+						break;	// not ok
+				}
+			if (j == numplanes)
+				break;
+		}
+		
+		if (i != numplanes)
+		{	// go along this plane
+			VectorCopy (new_velocity, ent->u.v.velocity);
+		}
+		else
+		{	// go along the crease
+			if (numplanes != 2)
+			{
+//				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+				VectorCopy (vec3_origin, ent->u.v.velocity);
+				return 7;
+			}
+			CrossProduct (planes[0], planes[1], dir);
+			d = DotProduct (dir, ent->u.v.velocity);
+			VectorScale (dir, d, ent->u.v.velocity);
+		}
+
+//
+// if original velocity is against the original velocity, stop dead
+// to avoid tiny occilations in sloping corners
+//
+		if (DotProduct (ent->u.v.velocity, primal_velocity) <= 0)
+		{
+			VectorCopy (vec3_origin, ent->u.v.velocity);
+			return blocked;
+		}
+	}
+
+	return blocked;
+}
+
+
+/*
+============
+SV_AddGravity
+
+============
+*/
+void SV_AddGravity (edict_t *ent)
+{
+	float	ent_gravity;
+
+#ifdef QUAKE2
+	if (ent->u.v.gravity)
+		ent_gravity = ent->u.v.gravity;
+	else
+		ent_gravity = 1.0;
+#else
+	eval_t	*val;
+
+	val = GetEdictFieldValue(ent, "gravity");
+	if (val && val->_float)
+		ent_gravity = val->_float;
+	else
+		ent_gravity = 1.0;
+#endif
+	ent->u.v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
+}
+
+
+/*
+===============================================================================
+
+PUSHMOVE
+
+===============================================================================
+*/
+
+/*
+============
+SV_PushEntity
+
+Does not change the entities velocity at all
+============
+*/
+trace_t SV_PushEntity (edict_t *ent, vec3_t push)
+{
+	trace_t	trace;
+	vec3_t	end;
+		
+	VectorAdd (ent->u.v.origin, push, end);
+
+	if (ent->u.v.movetype == MOVETYPE_FLYMISSILE)
+		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, MOVE_MISSILE, ent);
+	else if (ent->u.v.solid == SOLID_TRIGGER || ent->u.v.solid == SOLID_NOT)
+	// only clip against bmodels
+		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, MOVE_NOMONSTERS, ent);
+	else
+		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, MOVE_NORMAL, ent);	
+	
+	VectorCopy (trace.endpos, ent->u.v.origin);
+	SV_LinkEdict (ent, true);
+
+	if (trace.ent)
+		SV_Impact (ent, trace.ent);		
+
+	return trace;
+}					
+
+
+/*
+============
+SV_PushMove
+
+============
+*/
+void SV_PushMove (edict_t *pusher, float movetime)
+{
+	int			i, e;
+	edict_t		*check, *block;
+	vec3_t		mins, maxs, move;
+	vec3_t		entorig, pushorig;
+	int			num_moved;
+	edict_t		*moved_edict[MAX_EDICTS];
+	vec3_t		moved_from[MAX_EDICTS];
+
+	if (!pusher->u.v.velocity[0] && !pusher->u.v.velocity[1] && !pusher->u.v.velocity[2])
+	{
+		pusher->u.v.ltime += movetime;
+		return;
+	}
+
+	for (i=0 ; i<3 ; i++)
+	{
+		move[i] = pusher->u.v.velocity[i] * movetime;
+		mins[i] = pusher->u.v.absmin[i] + move[i];
+		maxs[i] = pusher->u.v.absmax[i] + move[i];
+	}
+
+	VectorCopy (pusher->u.v.origin, pushorig);
+	
+// move the pusher to it's final position
+
+	VectorAdd (pusher->u.v.origin, move, pusher->u.v.origin);
+	pusher->u.v.ltime += movetime;
+	SV_LinkEdict (pusher, false);
+
+
+// see if any solid entities are inside the final position
+	num_moved = 0;
+	check = NEXT_EDICT(sv.edicts);
+	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
+	{
+		if (check->free)
+			continue;
+		if (check->u.v.movetype == MOVETYPE_PUSH
+		|| check->u.v.movetype == MOVETYPE_NONE
+#ifdef QUAKE2
+		|| check->u.v.movetype == MOVETYPE_FOLLOW
+#endif
+		|| check->u.v.movetype == MOVETYPE_NOCLIP)
+			continue;
+
+	// if the entity is standing on the pusher, it will definately be moved
+		if ( ! ( ((int)check->u.v.flags & FL_ONGROUND)
+		&& PROG_TO_EDICT(check->u.v.groundentity) == pusher) )
+		{
+			if ( check->u.v.absmin[0] >= maxs[0]
+			|| check->u.v.absmin[1] >= maxs[1]
+			|| check->u.v.absmin[2] >= maxs[2]
+			|| check->u.v.absmax[0] <= mins[0]
+			|| check->u.v.absmax[1] <= mins[1]
+			|| check->u.v.absmax[2] <= mins[2] )
+				continue;
+
+		// see if the ent's bbox is inside the pusher's final position
+			if (!SV_TestEntityPosition (check))
+				continue;
+		}
+
+	// remove the onground flag for non-players
+		if (check->u.v.movetype != MOVETYPE_WALK)
+			check->u.v.flags = (int)check->u.v.flags & ~FL_ONGROUND;
+		
+		VectorCopy (check->u.v.origin, entorig);
+		VectorCopy (check->u.v.origin, moved_from[num_moved]);
+		moved_edict[num_moved] = check;
+		num_moved++;
+
+		// try moving the contacted entity 
+		pusher->u.v.solid = SOLID_NOT;
+		SV_PushEntity (check, move);
+		pusher->u.v.solid = SOLID_BSP;
+
+	// if it is still inside the pusher, block
+		block = SV_TestEntityPosition (check);
+		if (block)
+		{	// fail the move
+			if (check->u.v.mins[0] == check->u.v.maxs[0])
+				continue;
+			if (check->u.v.solid == SOLID_NOT || check->u.v.solid == SOLID_TRIGGER)
+			{	// corpse
+				check->u.v.mins[0] = check->u.v.mins[1] = 0;
+				VectorCopy (check->u.v.mins, check->u.v.maxs);
+				continue;
+			}
+			
+			VectorCopy (entorig, check->u.v.origin);
+			SV_LinkEdict (check, true);
+
+			VectorCopy (pushorig, pusher->u.v.origin);
+			SV_LinkEdict (pusher, false);
+			pusher->u.v.ltime -= movetime;
+
+			// if the pusher has a "blocked" function, call it
+			// otherwise, just stay in place until the obstacle is gone
+			if (pusher->u.v.blocked)
+			{
+				pr_global_struct->self = EDICT_TO_PROG(pusher);
+				pr_global_struct->other = EDICT_TO_PROG(check);
+				PR_ExecuteProgram (pusher->u.v.blocked);
+			}
+			
+		// move back any entities we already moved
+			for (i=0 ; i<num_moved ; i++)
+			{
+				VectorCopy (moved_from[i], moved_edict[i]->u.v.origin);
+				SV_LinkEdict (moved_edict[i], false);
+			}
+			return;
+		}	
+	}
+
+	
+}
+
+#ifdef QUAKE2
+/*
+============
+SV_PushRotate
+
+============
+*/
+void SV_PushRotate (edict_t *pusher, float movetime)
+{
+	int			i, e;
+	edict_t		*check, *block;
+	vec3_t		move, a, amove;
+	vec3_t		entorig, pushorig;
+	int			num_moved;
+	edict_t		*moved_edict[MAX_EDICTS];
+	vec3_t		moved_from[MAX_EDICTS];
+	vec3_t		org, org2;
+	vec3_t		forward, right, up;
+
+	if (!pusher->u.v.avelocity[0] && !pusher->u.v.avelocity[1] && !pusher->u.v.avelocity[2])
+	{
+		pusher->u.v.ltime += movetime;
+		return;
+	}
+
+	for (i=0 ; i<3 ; i++)
+		amove[i] = pusher->u.v.avelocity[i] * movetime;
+
+	VectorSubtract (vec3_origin, amove, a);
+	AngleVectors (a, forward, right, up);
+
+	VectorCopy (pusher->u.v.angles, pushorig);
+	
+// move the pusher to it's final position
+
+	VectorAdd (pusher->u.v.angles, amove, pusher->u.v.angles);
+	pusher->u.v.ltime += movetime;
+	SV_LinkEdict (pusher, false);
+
+
+// see if any solid entities are inside the final position
+	num_moved = 0;
+	check = NEXT_EDICT(sv.edicts);
+	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
+	{
+		if (check->free)
+			continue;
+		if (check->u.v.movetype == MOVETYPE_PUSH
+		|| check->u.v.movetype == MOVETYPE_NONE
+		|| check->u.v.movetype == MOVETYPE_FOLLOW
+		|| check->u.v.movetype == MOVETYPE_NOCLIP)
+			continue;
+
+	// if the entity is standing on the pusher, it will definately be moved
+		if ( ! ( ((int)check->u.v.flags & FL_ONGROUND)
+		&& PROG_TO_EDICT(check->u.v.groundentity) == pusher) )
+		{
+			if ( check->u.v.absmin[0] >= pusher->u.v.absmax[0]
+			|| check->u.v.absmin[1] >= pusher->u.v.absmax[1]
+			|| check->u.v.absmin[2] >= pusher->u.v.absmax[2]
+			|| check->u.v.absmax[0] <= pusher->u.v.absmin[0]
+			|| check->u.v.absmax[1] <= pusher->u.v.absmin[1]
+			|| check->u.v.absmax[2] <= pusher->u.v.absmin[2] )
+				continue;
+
+		// see if the ent's bbox is inside the pusher's final position
+			if (!SV_TestEntityPosition (check))
+				continue;
+		}
+
+	// remove the onground flag for non-players
+		if (check->u.v.movetype != MOVETYPE_WALK)
+			check->u.v.flags = (int)check->u.v.flags & ~FL_ONGROUND;
+		
+		VectorCopy (check->u.v.origin, entorig);
+		VectorCopy (check->u.v.origin, moved_from[num_moved]);
+		moved_edict[num_moved] = check;
+		num_moved++;
+
+		// calculate destination position
+		VectorSubtract (check->u.v.origin, pusher->u.v.origin, org);
+		org2[0] = DotProduct (org, forward);
+		org2[1] = -DotProduct (org, right);
+		org2[2] = DotProduct (org, up);
+		VectorSubtract (org2, org, move);
+
+		// try moving the contacted entity 
+		pusher->u.v.solid = SOLID_NOT;
+		SV_PushEntity (check, move);
+		pusher->u.v.solid = SOLID_BSP;
+
+	// if it is still inside the pusher, block
+		block = SV_TestEntityPosition (check);
+		if (block)
+		{	// fail the move
+			if (check->u.v.mins[0] == check->u.v.maxs[0])
+				continue;
+			if (check->u.v.solid == SOLID_NOT || check->u.v.solid == SOLID_TRIGGER)
+			{	// corpse
+				check->u.v.mins[0] = check->u.v.mins[1] = 0;
+				VectorCopy (check->u.v.mins, check->u.v.maxs);
+				continue;
+			}
+			
+			VectorCopy (entorig, check->u.v.origin);
+			SV_LinkEdict (check, true);
+
+			VectorCopy (pushorig, pusher->u.v.angles);
+			SV_LinkEdict (pusher, false);
+			pusher->u.v.ltime -= movetime;
+
+			// if the pusher has a "blocked" function, call it
+			// otherwise, just stay in place until the obstacle is gone
+			if (pusher->u.v.blocked)
+			{
+				pr_global_struct->self = EDICT_TO_PROG(pusher);
+				pr_global_struct->other = EDICT_TO_PROG(check);
+				PR_ExecuteProgram (pusher->u.v.blocked);
+			}
+			
+		// move back any entities we already moved
+			for (i=0 ; i<num_moved ; i++)
+			{
+				VectorCopy (moved_from[i], moved_edict[i]->u.v.origin);
+				VectorSubtract (moved_edict[i]->u.v.angles, amove, moved_edict[i]->u.v.angles);
+				SV_LinkEdict (moved_edict[i], false);
+			}
+			return;
+		}
+		else
+		{
+			VectorAdd (check->u.v.angles, amove, check->u.v.angles);
+		}
+	}
+
+	
+}
+#endif
+
+/*
+================
+SV_Physics_Pusher
+
+================
+*/
+void SV_Physics_Pusher (edict_t *ent)
+{
+	float	thinktime;
+	float	oldltime;
+	float	movetime;
+
+	oldltime = ent->u.v.ltime;
+	
+	thinktime = ent->u.v.nextthink;
+	if (thinktime < ent->u.v.ltime + host_frametime)
+	{
+		movetime = thinktime - ent->u.v.ltime;
+		if (movetime < 0)
+			movetime = 0;
+	}
+	else
+		movetime = host_frametime;
+
+	if (movetime)
+	{
+#ifdef QUAKE2
+		if (ent->u.v.avelocity[0] || ent->u.v.avelocity[1] || ent->u.v.avelocity[2])
+			SV_PushRotate (ent, movetime);
+		else
+#endif
+			SV_PushMove (ent, movetime);	// advances ent->u.v.ltime if not blocked
+	}
+		
+	if (thinktime > oldltime && thinktime <= ent->u.v.ltime)
+	{
+		ent->u.v.nextthink = 0;
+		pr_global_struct->time = sv.time;
+		pr_global_struct->self = EDICT_TO_PROG(ent);
+		pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
+		PR_ExecuteProgram (ent->u.v.think);
+		if (ent->free)
+			return;
+	}
+
+}
+
+
+/*
+===============================================================================
+
+CLIENT MOVEMENT
+
+===============================================================================
+*/
+
+/*
+=============
+SV_CheckStuck
+
+This is a big hack to try and fix the rare case of getting stuck in the world
+clipping hull.
+=============
+*/
+void SV_CheckStuck (edict_t *ent)
+{
+	int		i, j;
+	int		z;
+	vec3_t	org;
+
+	if (!SV_TestEntityPosition(ent))
+	{
+		VectorCopy (ent->u.v.origin, ent->u.v.oldorigin);
+		return;
+	}
+
+	VectorCopy (ent->u.v.origin, org);
+	VectorCopy (ent->u.v.oldorigin, ent->u.v.origin);
+	if (!SV_TestEntityPosition(ent))
+	{
+		Con_DPrintf ("Unstuck.\n");
+		SV_LinkEdict (ent, true);
+		return;
+	}
+	
+	for (z=0 ; z< 18 ; z++)
+		for (i=-1 ; i <= 1 ; i++)
+			for (j=-1 ; j <= 1 ; j++)
+			{
+				ent->u.v.origin[0] = org[0] + i;
+				ent->u.v.origin[1] = org[1] + j;
+				ent->u.v.origin[2] = org[2] + z;
+				if (!SV_TestEntityPosition(ent))
+				{
+					Con_DPrintf ("Unstuck.\n");
+					SV_LinkEdict (ent, true);
+					return;
+				}
+			}
+			
+	VectorCopy (org, ent->u.v.origin);
+	Con_DPrintf ("player is stuck.\n");
+}
+
+
+/*
+=============
+SV_CheckWater
+=============
+*/
+qboolean SV_CheckWater (edict_t *ent)
+{
+	vec3_t	point;
+	int		cont;
+#ifdef QUAKE2
+	int		truecont;
+#endif
+
+	point[0] = ent->u.v.origin[0];
+	point[1] = ent->u.v.origin[1];
+	point[2] = ent->u.v.origin[2] + ent->u.v.mins[2] + 1;	
+	
+	ent->u.v.waterlevel = 0;
+	ent->u.v.watertype = CONTENTS_EMPTY;
+	cont = SV_PointContents (point);
+	if (cont <= CONTENTS_WATER)
+	{
+#ifdef QUAKE2
+		truecont = SV_TruePointContents (point);
+#endif
+		ent->u.v.watertype = cont;
+		ent->u.v.waterlevel = 1;
+		point[2] = ent->u.v.origin[2] + (ent->u.v.mins[2] + ent->u.v.maxs[2])*0.5;
+		cont = SV_PointContents (point);
+		if (cont <= CONTENTS_WATER)
+		{
+			ent->u.v.waterlevel = 2;
+			point[2] = ent->u.v.origin[2] + ent->u.v.view_ofs[2];
+			cont = SV_PointContents (point);
+			if (cont <= CONTENTS_WATER)
+				ent->u.v.waterlevel = 3;
+		}
+#ifdef QUAKE2
+		if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)
+		{
+			static vec3_t current_table[] =
+			{
+				{1, 0, 0},
+				{0, 1, 0},
+				{-1, 0, 0},
+				{0, -1, 0},
+				{0, 0, 1},
+				{0, 0, -1}
+			};
+
+			VectorMA (ent->u.v.basevelocity, 150.0*ent->u.v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->u.v.basevelocity);
+		}
+#endif
+	}
+	
+	return ent->u.v.waterlevel > 1;
+}
+
+/*
+============
+SV_WallFriction
+
+============
+*/
+void SV_WallFriction (edict_t *ent, trace_t *trace)
+{
+	vec3_t		forward, right, up;
+	float		d, i;
+	vec3_t		into, side;
+	
+	AngleVectors (ent->u.v.v_angle, forward, right, up);
+	d = DotProduct (trace->plane.normal, forward);
+	
+	d += 0.5;
+	if (d >= 0)
+		return;
+		
+// cut the tangential velocity
+	i = DotProduct (trace->plane.normal, ent->u.v.velocity);
+	VectorScale (trace->plane.normal, i, into);
+	VectorSubtract (ent->u.v.velocity, into, side);
+	
+	ent->u.v.velocity[0] = side[0] * (1 + d);
+	ent->u.v.velocity[1] = side[1] * (1 + d);
+}
+
+/*
+=====================
+SV_TryUnstick
+
+Player has come to a dead stop, possibly due to the problem with limited
+float precision at some angle joins in the BSP hull.
+
+Try fixing by pushing one pixel in each direction.
+
+This is a hack, but in the interest of good gameplay...
+======================
+*/
+int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
+{
+	int		i;
+	vec3_t	oldorg;
+	vec3_t	dir;
+	int		clip;
+	trace_t	steptrace;
+	
+	VectorCopy (ent->u.v.origin, oldorg);
+	VectorCopy (vec3_origin, dir);
+
+	for (i=0 ; i<8 ; i++)
+	{
+// try pushing a little in an axial direction
+		switch (i)
+		{
+			case 0:	dir[0] = 2; dir[1] = 0; break;
+			case 1:	dir[0] = 0; dir[1] = 2; break;
+			case 2:	dir[0] = -2; dir[1] = 0; break;
+			case 3:	dir[0] = 0; dir[1] = -2; break;
+			case 4:	dir[0] = 2; dir[1] = 2; break;
+			case 5:	dir[0] = -2; dir[1] = 2; break;
+			case 6:	dir[0] = 2; dir[1] = -2; break;
+			case 7:	dir[0] = -2; dir[1] = -2; break;
+		}
+		
+		SV_PushEntity (ent, dir);
+
+// retry the original move
+		ent->u.v.velocity[0] = oldvel[0];
+		ent->u.v. velocity[1] = oldvel[1];
+		ent->u.v. velocity[2] = 0;
+		clip = SV_FlyMove (ent, 0.1, &steptrace);
+
+		if ( fabs(oldorg[1] - ent->u.v.origin[1]) > 4
+		|| fabs(oldorg[0] - ent->u.v.origin[0]) > 4 )
+		{
+//Con_DPrintf ("unstuck!\n");
+			return clip;
+		}
+			
+// go back to the original pos and try again
+		VectorCopy (oldorg, ent->u.v.origin);
+	}
+	
+	VectorCopy (vec3_origin, ent->u.v.velocity);
+	return 7;		// still not moving
+}
+
+/*
+=====================
+SV_WalkMove
+
+Only used by players
+======================
+*/
+#define	STEPSIZE	18
+void SV_WalkMove (edict_t *ent)
+{
+	vec3_t		upmove, downmove;
+	vec3_t		oldorg, oldvel;
+	vec3_t		nosteporg, nostepvel;
+	int			clip;
+	int			oldonground;
+	trace_t		steptrace, downtrace;
+	
+//
+// do a regular slide move unless it looks like you ran into a step
+//
+	oldonground = (int)ent->u.v.flags & FL_ONGROUND;
+	ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
+	
+	VectorCopy (ent->u.v.origin, oldorg);
+	VectorCopy (ent->u.v.velocity, oldvel);
+	
+	clip = SV_FlyMove (ent, host_frametime, &steptrace);
+
+	if ( !(clip & 2) )
+		return;		// move didn't block on a step
+
+	if (!oldonground && ent->u.v.waterlevel == 0)
+		return;		// don't stair up while jumping
+	
+	if (ent->u.v.movetype != MOVETYPE_WALK)
+		return;		// gibbed by a trigger
+	
+	if (sv_nostep.value)
+		return;
+	
+	if ( (int)sv_player->u.v.flags & FL_WATERJUMP )
+		return;
+
+	VectorCopy (ent->u.v.origin, nosteporg);
+	VectorCopy (ent->u.v.velocity, nostepvel);
+
+//
+// try moving up and forward to go up a step
+//
+	VectorCopy (oldorg, ent->u.v.origin);	// back to start pos
+
+	VectorCopy (vec3_origin, upmove);
+	VectorCopy (vec3_origin, downmove);
+	upmove[2] = STEPSIZE;
+	downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
+
+// move up
+	SV_PushEntity (ent, upmove);	// FIXME: don't link?
+
+// move forward
+	ent->u.v.velocity[0] = oldvel[0];
+	ent->u.v. velocity[1] = oldvel[1];
+	ent->u.v. velocity[2] = 0;
+	clip = SV_FlyMove (ent, host_frametime, &steptrace);
+
+// check for stuckness, possibly due to the limited precision of floats
+// in the clipping hulls
+	if (clip)
+	{
+		if ( fabs(oldorg[1] - ent->u.v.origin[1]) < 0.03125
+		&& fabs(oldorg[0] - ent->u.v.origin[0]) < 0.03125 )
+		{	// stepping up didn't make any progress
+			clip = SV_TryUnstick (ent, oldvel);
+		}
+	}
+	
+// extra friction based on view angle
+	if ( clip & 2 )
+		SV_WallFriction (ent, &steptrace);
+
+// move down
+	downtrace = SV_PushEntity (ent, downmove);	// FIXME: don't link?
+
+	if (downtrace.plane.normal[2] > 0.7)
+	{
+		if (ent->u.v.solid == SOLID_BSP)
+		{
+			ent->u.v.flags =	(int)ent->u.v.flags | FL_ONGROUND;
+			ent->u.v.groundentity = EDICT_TO_PROG(downtrace.ent);
+		}
+	}
+	else
+	{
+// if the push down didn't end up on good ground, use the move without
+// the step up.  This happens near wall / slope combinations, and can
+// cause the player to hop up higher on a slope too steep to climb	
+		VectorCopy (nosteporg, ent->u.v.origin);
+		VectorCopy (nostepvel, ent->u.v.velocity);
+	}
+}
+
+
+/*
+================
+SV_Physics_Client
+
+Player character actions
+================
+*/
+void SV_Physics_Client (edict_t	*ent, int num)
+{
+	if ( ! svs.clients[num-1].active )
+		return;		// unconnected slot
+
+//
+// call standard client pre-think
+//	
+	pr_global_struct->time = sv.time;
+	pr_global_struct->self = EDICT_TO_PROG(ent);
+	PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
+	
+//
+// do a move
+//
+	SV_CheckVelocity (ent);
+
+//
+// decide which move function to call
+//
+	switch ((int)ent->u.v.movetype)
+	{
+	case MOVETYPE_NONE:
+		if (!SV_RunThink (ent))
+			return;
+		break;
+
+	case MOVETYPE_WALK:
+		if (!SV_RunThink (ent))
+			return;
+		if (!SV_CheckWater (ent) && ! ((int)ent->u.v.flags & FL_WATERJUMP) )
+			SV_AddGravity (ent);
+		SV_CheckStuck (ent);
+#ifdef QUAKE2
+		VectorAdd (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
+#endif
+		SV_WalkMove (ent);
+
+#ifdef QUAKE2
+		VectorSubtract (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
+#endif
+		break;
+		
+	case MOVETYPE_TOSS:
+	case MOVETYPE_BOUNCE:
+		SV_Physics_Toss (ent);
+		break;
+
+	case MOVETYPE_FLY:
+		if (!SV_RunThink (ent))
+			return;
+		SV_FlyMove (ent, host_frametime, NULL);
+		break;
+		
+	case MOVETYPE_NOCLIP:
+		if (!SV_RunThink (ent))
+			return;
+		VectorMA (ent->u.v.origin, host_frametime, ent->u.v.velocity, ent->u.v.origin);
+		break;
+		
+	default:
+		Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->u.v.movetype);
+	}
+
+//
+// call standard player post-think
+//		
+	SV_LinkEdict (ent, true);
+
+	pr_global_struct->time = sv.time;
+	pr_global_struct->self = EDICT_TO_PROG(ent);
+	PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
+}
+
+//============================================================================
+
+/*
+=============
+SV_Physics_None
+
+Non moving objects can only think
+=============
+*/
+void SV_Physics_None (edict_t *ent)
+{
+// regular thinking
+	SV_RunThink (ent);
+}
+
+#ifdef QUAKE2
+/*
+=============
+SV_Physics_Follow
+
+Entities that are "stuck" to another entity
+=============
+*/
+void SV_Physics_Follow (edict_t *ent)
+{
+// regular thinking
+	SV_RunThink (ent);
+	VectorAdd (PROG_TO_EDICT(ent->u.v.aiment)->u.v.origin, ent->u.v.v_angle, ent->u.v.origin);
+	SV_LinkEdict (ent, true);
+}
+#endif
+
+/*
+=============
+SV_Physics_Noclip
+
+A moving object that doesn't obey physics
+=============
+*/
+void SV_Physics_Noclip (edict_t *ent)
+{
+// regular thinking
+	if (!SV_RunThink (ent))
+		return;
+	
+	VectorMA (ent->u.v.angles, host_frametime, ent->u.v.avelocity, ent->u.v.angles);
+	VectorMA (ent->u.v.origin, host_frametime, ent->u.v.velocity, ent->u.v.origin);
+
+	SV_LinkEdict (ent, false);
+}
+
+/*
+==============================================================================
+
+TOSS / BOUNCE
+
+==============================================================================
+*/
+
+/*
+=============
+SV_CheckWaterTransition
+
+=============
+*/
+void SV_CheckWaterTransition (edict_t *ent)
+{
+	int		cont;
+#ifdef QUAKE2
+	vec3_t	point;
+	
+	point[0] = ent->u.v.origin[0];
+	point[1] = ent->u.v.origin[1];
+	point[2] = ent->u.v.origin[2] + ent->u.v.mins[2] + 1;	
+	cont = SV_PointContents (point);
+#else
+	cont = SV_PointContents (ent->u.v.origin);
+#endif
+	if (!ent->u.v.watertype)
+	{	// just spawned here
+		ent->u.v.watertype = cont;
+		ent->u.v.waterlevel = 1;
+		return;
+	}
+	
+	if (cont <= CONTENTS_WATER)
+	{
+		if (ent->u.v.watertype == CONTENTS_EMPTY)
+		{	// just crossed into water
+			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
+		}		
+		ent->u.v.watertype = cont;
+		ent->u.v.waterlevel = 1;
+	}
+	else
+	{
+		if (ent->u.v.watertype != CONTENTS_EMPTY)
+		{	// just crossed into water
+			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
+		}		
+		ent->u.v.watertype = CONTENTS_EMPTY;
+		ent->u.v.waterlevel = cont;
+	}
+}
+
+/*
+=============
+SV_Physics_Toss
+
+Toss, bounce, and fly movement.  When onground, do nothing.
+=============
+*/
+void SV_Physics_Toss (edict_t *ent)
+{
+	trace_t	trace;
+	vec3_t	move;
+	float	backoff;
+#ifdef QUAKE2
+	edict_t	*groundentity;
+
+	groundentity = PROG_TO_EDICT(ent->u.v.groundentity);
+	if ((int)groundentity->u.v.flags & FL_CONVEYOR)
+		VectorScale(groundentity->u.v.movedir, groundentity->u.v.speed, ent->u.v.basevelocity);
+	else
+		VectorCopy(vec_origin, ent->u.v.basevelocity);
+	SV_CheckWater (ent);
+#endif
+	// regular thinking
+	if (!SV_RunThink (ent))
+		return;
+
+#ifdef QUAKE2
+	if (ent->u.v.velocity[2] > 0)
+		ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
+
+	if ( ((int)ent->u.v.flags & FL_ONGROUND) )
+//@@
+		if (VectorCompare(ent->u.v.basevelocity, vec_origin))
+			return;
+
+	SV_CheckVelocity (ent);
+
+// add gravity
+	if (! ((int)ent->u.v.flags & FL_ONGROUND)
+		&& ent->u.v.movetype != MOVETYPE_FLY
+		&& ent->u.v.movetype != MOVETYPE_BOUNCEMISSILE
+		&& ent->u.v.movetype != MOVETYPE_FLYMISSILE)
+			SV_AddGravity (ent);
+
+#else
+// if onground, return without moving
+	if ( ((int)ent->u.v.flags & FL_ONGROUND) )
+		return;
+
+	SV_CheckVelocity (ent);
+
+// add gravity
+	if (ent->u.v.movetype != MOVETYPE_FLY
+	&& ent->u.v.movetype != MOVETYPE_FLYMISSILE)
+		SV_AddGravity (ent);
+#endif
+
+// move angles
+	VectorMA (ent->u.v.angles, host_frametime, ent->u.v.avelocity, ent->u.v.angles);
+
+// move origin
+#ifdef QUAKE2
+	VectorAdd (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
+#endif
+	VectorScale (ent->u.v.velocity, host_frametime, move);
+	trace = SV_PushEntity (ent, move);
+#ifdef QUAKE2
+	VectorSubtract (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
+#endif
+	if (trace.fraction == 1)
+		return;
+	if (ent->free)
+		return;
+	
+	if (ent->u.v.movetype == MOVETYPE_BOUNCE)
+		backoff = 1.5;
+#ifdef QUAKE2
+	else if (ent->u.v.movetype == MOVETYPE_BOUNCEMISSILE)
+		backoff = 2.0;
+#endif
+	else
+		backoff = 1;
+
+	ClipVelocity (ent->u.v.velocity, trace.plane.normal, ent->u.v.velocity, backoff);
+
+// stop if on ground
+	if (trace.plane.normal[2] > 0.7)
+	{		
+#ifdef QUAKE2
+		if (ent->u.v.velocity[2] < 60 || (ent->u.v.movetype != MOVETYPE_BOUNCE && ent->u.v.movetype != MOVETYPE_BOUNCEMISSILE))
+#else
+		if (ent->u.v.velocity[2] < 60 || ent->u.v.movetype != MOVETYPE_BOUNCE)
+#endif
+		{
+			ent->u.v.flags = (int)ent->u.v.flags | FL_ONGROUND;
+			ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
+			VectorCopy (vec3_origin, ent->u.v.velocity);
+			VectorCopy (vec3_origin, ent->u.v.avelocity);
+		}
+	}
+	
+// check for in water
+	SV_CheckWaterTransition (ent);
+}
+
+/*
+===============================================================================
+
+STEPPING MOVEMENT
+
+===============================================================================
+*/
+
+/*
+=============
+SV_Physics_Step
+
+Monsters freefall when they don't have a ground entity, otherwise
+all movement is done with discrete steps.
+
+This is also used for objects that have become still on the ground, but
+will fall if the floor is pulled out from under them.
+=============
+*/
+#ifdef QUAKE2
+void SV_Physics_Step (edict_t *ent)
+{
+	qboolean	wasonground;
+	qboolean	inwater;
+	qboolean	hitsound = false;
+	float		*vel;
+	float		speed, newspeed, control;
+	float		friction;
+	edict_t		*groundentity;
+
+	groundentity = PROG_TO_EDICT(ent->u.v.groundentity);
+	if ((int)groundentity->u.v.flags & FL_CONVEYOR)
+		VectorScale(groundentity->u.v.movedir, groundentity->u.v.speed, ent->u.v.basevelocity);
+	else
+		VectorCopy(vec_origin, ent->u.v.basevelocity);
+//@@
+	pr_global_struct->time = sv.time;
+	pr_global_struct->self = EDICT_TO_PROG(ent);
+	PF_WaterMove();
+
+	SV_CheckVelocity (ent);
+
+	wasonground = (int)ent->u.v.flags & FL_ONGROUND;
+//	ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
+
+	// add gravity except:
+	//   flying monsters
+	//   swimming monsters who are in the water
+	inwater = SV_CheckWater(ent);
+	if (! wasonground)
+		if (!((int)ent->u.v.flags & FL_FLY))
+			if (!(((int)ent->u.v.flags & FL_SWIM) && (ent->u.v.waterlevel > 0)))
+			{
+				if (ent->u.v.velocity[2] < sv_gravity.value*-0.1)
+					hitsound = true;
+				if (!inwater)
+					SV_AddGravity (ent);
+			}
+
+	if (!VectorCompare(ent->u.v.velocity, vec_origin) || !VectorCompare(ent->u.v.basevelocity, vec_origin))
+	{
+		ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
+		// apply friction
+		// let dead monsters who aren't completely onground slide
+		if (wasonground)
+			if (!(ent->u.v.health <= 0.0 && !SV_CheckBottom(ent)))
+			{
+				vel = ent->u.v.velocity;
+				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
+				if (speed)
+				{
+					friction = sv_friction.value;
+
+					control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
+					newspeed = speed - host_frametime*control*friction;
+
+					if (newspeed < 0)
+						newspeed = 0;
+					newspeed /= speed;
+
+					vel[0] = vel[0] * newspeed;
+					vel[1] = vel[1] * newspeed;
+				}
+			}
+
+		VectorAdd (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
+		SV_FlyMove (ent, host_frametime, NULL);
+		VectorSubtract (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
+
+		// determine if it's on solid ground at all
+		{
+			vec3_t	mins, maxs, point;
+			int		x, y;
+		
+			VectorAdd (ent->u.v.origin, ent->u.v.mins, mins);
+			VectorAdd (ent->u.v.origin, ent->u.v.maxs, maxs);
+
+			point[2] = mins[2] - 1;
+			for	(x=0 ; x<=1 ; x++)
+				for	(y=0 ; y<=1 ; y++)
+				{
+					point[0] = x ? maxs[0] : mins[0];
+					point[1] = y ? maxs[1] : mins[1];
+					if (SV_PointContents (point) == CONTENTS_SOLID)
+					{
+						ent->u.v.flags = (int)ent->u.v.flags | FL_ONGROUND;
+						break;
+					}
+				}
+
+		}
+
+		SV_LinkEdict (ent, true);
+
+		if ((int)ent->u.v.flags & FL_ONGROUND)
+			if (!wasonground)
+				if (hitsound)
+					SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
+	}
+
+// regular thinking
+	SV_RunThink (ent);
+	SV_CheckWaterTransition (ent);
+}
+#else
+void SV_Physics_Step (edict_t *ent)
+{
+	qboolean	hitsound;
+
+// freefall if not onground
+	if ( ! ((int)ent->u.v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
+	{
+		if (ent->u.v.velocity[2] < sv_gravity.value*-0.1)
+			hitsound = true;
+		else
+			hitsound = false;
+
+		SV_AddGravity (ent);
+		SV_CheckVelocity (ent);
+		SV_FlyMove (ent, host_frametime, NULL);
+		SV_LinkEdict (ent, true);
+
+		if ( (int)ent->u.v.flags & FL_ONGROUND )	// just hit ground
+		{
+			if (hitsound)
+				SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
+		}
+	}
+
+// regular thinking
+	SV_RunThink (ent);
+	
+	SV_CheckWaterTransition (ent);
+}
+#endif
+
+//============================================================================
+
+/*
+================
+SV_Physics
+
+================
+*/
+void SV_Physics (void)
+{
+	int		i;
+	edict_t	*ent;
+
+// let the progs know that a new frame has started
+	pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
+	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
+	pr_global_struct->time = sv.time;
+	PR_ExecuteProgram (pr_global_struct->StartFrame);
+
+//SV_CheckAllEnts ();
+
+//
+// treat each object in turn
+//
+	ent = sv.edicts;
+	for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
+	{
+		if (ent->free)
+			continue;
+
+		if (pr_global_struct->force_retouch)
+		{
+			SV_LinkEdict (ent, true);	// force retouch even for stationary
+		}
+
+		if (i > 0 && i <= svs.maxclients)
+			SV_Physics_Client (ent, i);
+		else if (ent->u.v.movetype == MOVETYPE_PUSH)
+			SV_Physics_Pusher (ent);
+		else if (ent->u.v.movetype == MOVETYPE_NONE)
+			SV_Physics_None (ent);
+#ifdef QUAKE2
+		else if (ent->u.v.movetype == MOVETYPE_FOLLOW)
+			SV_Physics_Follow (ent);
+#endif
+		else if (ent->u.v.movetype == MOVETYPE_NOCLIP)
+			SV_Physics_Noclip (ent);
+		else if (ent->u.v.movetype == MOVETYPE_STEP)
+			SV_Physics_Step (ent);
+		else if (ent->u.v.movetype == MOVETYPE_TOSS 
+		|| ent->u.v.movetype == MOVETYPE_BOUNCE
+#ifdef QUAKE2
+		|| ent->u.v.movetype == MOVETYPE_BOUNCEMISSILE
+#endif
+		|| ent->u.v.movetype == MOVETYPE_FLY
+		|| ent->u.v.movetype == MOVETYPE_FLYMISSILE)
+			SV_Physics_Toss (ent);
+		else
+			Sys_Error ("SV_Physics: bad movetype %i", (int)ent->u.v.movetype);			
+	}
+	
+	if (pr_global_struct->force_retouch)
+		pr_global_struct->force_retouch--;	
+
+	sv.time += host_frametime;
+}
+
+
+#ifdef QUAKE2
+trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
+{
+	edict_t	tempent, *tent;
+	trace_t	trace;
+	vec3_t	move;
+	vec3_t	end;
+	double	save_frametime;
+//	extern particle_t	*active_particles, *free_particles;
+//	particle_t	*p;
+
+
+	save_frametime = host_frametime;
+	host_frametime = 0.05;
+
+	memcpy(&tempent, ent, sizeof(edict_t));
+	tent = &tempent;
+
+	while (1)
+	{
+		SV_CheckVelocity (tent);
+		SV_AddGravity (tent);
+		VectorMA (tent->u.v.angles, host_frametime, tent->u.v.avelocity, tent->u.v.angles);
+		VectorScale (tent->u.v.velocity, host_frametime, move);
+		VectorAdd (tent->u.v.origin, move, end);
+		trace = SV_Move (tent->u.v.origin, tent->u.v.mins, tent->u.v.maxs, end, MOVE_NORMAL, tent);	
+		VectorCopy (trace.endpos, tent->u.v.origin);
+
+//		p = free_particles;
+//		if (p)
+//		{
+//			free_particles = p->next;
+//			p->next = active_particles;
+//			active_particles = p;
+//		
+//			p->die = 256;
+//			p->color = 15;
+//			p->type = pt_static;
+//			VectorCopy (vec3_origin, p->vel);
+//			VectorCopy (tent->u.v.origin, p->org);
+//		}
+
+		if (trace.ent)
+			if (trace.ent != ignore)
+				break;
+	}
+//	p->color = 224;
+	host_frametime = save_frametime;
+	return trace;
+}
+#endif
diff --git a/quake/src/WinQuake/sv_user.c b/quake/src/WinQuake/sv_user.cpp
old mode 100644
new mode 100755
similarity index 82%
rename from quake/src/WinQuake/sv_user.c
rename to quake/src/WinQuake/sv_user.cpp
index 42c0329..960597c
--- a/quake/src/WinQuake/sv_user.c
+++ b/quake/src/WinQuake/sv_user.cpp
@@ -1,629 +1,629 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// sv_user.c -- server code for moving users

-

-#include "quakedef.h"

-

-edict_t	*sv_player;

-

-extern	cvar_t	sv_friction;

-cvar_t	sv_edgefriction = {"edgefriction", "2"};

-extern	cvar_t	sv_stopspeed;

-

-static	vec3_t		forward, right, up;

-

-vec3_t	wishdir;

-float	wishspeed;

-

-// world

-float	*angles;

-float	*origin;

-float	*velocity;

-

-qboolean	onground;

-

-usercmd_t	cmd;

-

-cvar_t	sv_idealpitchscale = {"sv_idealpitchscale","0.8"};

-

-

-/*

-===============

-SV_SetIdealPitch

-===============

-*/

-#define	MAX_FORWARD	6

-void SV_SetIdealPitch (void)

-{

-	float	angleval, sinval, cosval;

-	trace_t	tr;

-	vec3_t	top, bottom;

-	float	z[MAX_FORWARD];

-	int		i, j;

-	int		step, dir, steps;

-

-	if (!((int)sv_player->v.flags & FL_ONGROUND))

-		return;

-		

-	angleval = sv_player->v.angles[YAW] * M_PI*2 / 360;

-	sinval = sin(angleval);

-	cosval = cos(angleval);

-

-	for (i=0 ; i<MAX_FORWARD ; i++)

-	{

-		top[0] = sv_player->v.origin[0] + cosval*(i+3)*12;

-		top[1] = sv_player->v.origin[1] + sinval*(i+3)*12;

-		top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2];

-		

-		bottom[0] = top[0];

-		bottom[1] = top[1];

-		bottom[2] = top[2] - 160;

-		

-		tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player);

-		if (tr.allsolid)

-			return;	// looking at a wall, leave ideal the way is was

-

-		if (tr.fraction == 1)

-			return;	// near a dropoff

-		

-		z[i] = top[2] + tr.fraction*(bottom[2]-top[2]);

-	}

-	

-	dir = 0;

-	steps = 0;

-	for (j=1 ; j<i ; j++)

-	{

-		step = z[j] - z[j-1];

-		if (step > -ON_EPSILON && step < ON_EPSILON)

-			continue;

-

-		if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) )

-			return;		// mixed changes

-

-		steps++;	

-		dir = step;

-	}

-	

-	if (!dir)

-	{

-		sv_player->v.idealpitch = 0;

-		return;

-	}

-	

-	if (steps < 2)

-		return;

-	sv_player->v.idealpitch = -dir * sv_idealpitchscale.value;

-}

-

-

-/*

-==================

-SV_UserFriction

-

-==================

-*/

-void SV_UserFriction (void)

-{

-	float	*vel;

-	float	speed, newspeed, control;

-	vec3_t	start, stop;

-	float	friction;

-	trace_t	trace;

-	

-	vel = velocity;

-	

-	speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);

-	if (!speed)

-		return;

-

-// if the leading edge is over a dropoff, increase friction

-	start[0] = stop[0] = origin[0] + vel[0]/speed*16;

-	start[1] = stop[1] = origin[1] + vel[1]/speed*16;

-	start[2] = origin[2] + sv_player->v.mins[2];

-	stop[2] = start[2] - 34;

-

-	trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player);

-

-	if (trace.fraction == 1.0)

-		friction = sv_friction.value*sv_edgefriction.value;

-	else

-		friction = sv_friction.value;

-

-// apply friction	

-	control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;

-	newspeed = speed - host_frametime*control*friction;

-	

-	if (newspeed < 0)

-		newspeed = 0;

-	newspeed /= speed;

-

-	vel[0] = vel[0] * newspeed;

-	vel[1] = vel[1] * newspeed;

-	vel[2] = vel[2] * newspeed;

-}

-

-/*

-==============

-SV_Accelerate

-==============

-*/

-cvar_t	sv_maxspeed = {"sv_maxspeed", "320", false, true};

-cvar_t	sv_accelerate = {"sv_accelerate", "10"};

-#if 0

-void SV_Accelerate (vec3_t wishvel)

-{

-	int			i;

-	float		addspeed, accelspeed;

-	vec3_t		pushvec;

-

-	if (wishspeed == 0)

-		return;

-

-	VectorSubtract (wishvel, velocity, pushvec);

-	addspeed = VectorNormalize (pushvec);

-

-	accelspeed = sv_accelerate.value*host_frametime*addspeed;

-	if (accelspeed > addspeed)

-		accelspeed = addspeed;

-	

-	for (i=0 ; i<3 ; i++)

-		velocity[i] += accelspeed*pushvec[i];	

-}

-#endif

-void SV_Accelerate (void)

-{

-	int			i;

-	float		addspeed, accelspeed, currentspeed;

-

-	currentspeed = DotProduct (velocity, wishdir);

-	addspeed = wishspeed - currentspeed;

-	if (addspeed <= 0)

-		return;

-	accelspeed = sv_accelerate.value*host_frametime*wishspeed;

-	if (accelspeed > addspeed)

-		accelspeed = addspeed;

-	

-	for (i=0 ; i<3 ; i++)

-		velocity[i] += accelspeed*wishdir[i];	

-}

-

-void SV_AirAccelerate (vec3_t wishveloc)

-{

-	int			i;

-	float		addspeed, wishspd, accelspeed, currentspeed;

-		

-	wishspd = VectorNormalize (wishveloc);

-	if (wishspd > 30)

-		wishspd = 30;

-	currentspeed = DotProduct (velocity, wishveloc);

-	addspeed = wishspd - currentspeed;

-	if (addspeed <= 0)

-		return;

-//	accelspeed = sv_accelerate.value * host_frametime;

-	accelspeed = sv_accelerate.value*wishspeed * host_frametime;

-	if (accelspeed > addspeed)

-		accelspeed = addspeed;

-	

-	for (i=0 ; i<3 ; i++)

-		velocity[i] += accelspeed*wishveloc[i];	

-}

-

-

-void DropPunchAngle (void)

-{

-	float	len;

-	

-	len = VectorNormalize (sv_player->v.punchangle);

-	

-	len -= 10*host_frametime;

-	if (len < 0)

-		len = 0;

-	VectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle);

-}

-

-/*

-===================

-SV_WaterMove

-

-===================

-*/

-void SV_WaterMove (void)

-{

-	int		i;

-	vec3_t	wishvel;

-	float	speed, newspeed, wishspeed, addspeed, accelspeed;

-

-//

-// user intentions

-//

-	AngleVectors (sv_player->v.v_angle, forward, right, up);

-

-	for (i=0 ; i<3 ; i++)

-		wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;

-

-	if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)

-		wishvel[2] -= 60;		// drift towards bottom

-	else

-		wishvel[2] += cmd.upmove;

-

-	wishspeed = Length(wishvel);

-	if (wishspeed > sv_maxspeed.value)

-	{

-		VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);

-		wishspeed = sv_maxspeed.value;

-	}

-	wishspeed *= 0.7;

-

-//

-// water friction

-//

-	speed = Length (velocity);

-	if (speed)

-	{

-		newspeed = speed - host_frametime * speed * sv_friction.value;

-		if (newspeed < 0)

-			newspeed = 0;	

-		VectorScale (velocity, newspeed/speed, velocity);

-	}

-	else

-		newspeed = 0;

-	

-//

-// water acceleration

-//

-	if (!wishspeed)

-		return;

-

-	addspeed = wishspeed - newspeed;

-	if (addspeed <= 0)

-		return;

-

-	VectorNormalize (wishvel);

-	accelspeed = sv_accelerate.value * wishspeed * host_frametime;

-	if (accelspeed > addspeed)

-		accelspeed = addspeed;

-

-	for (i=0 ; i<3 ; i++)

-		velocity[i] += accelspeed * wishvel[i];

-}

-

-void SV_WaterJump (void)

-{

-	if (sv.time > sv_player->v.teleport_time

-	|| !sv_player->v.waterlevel)

-	{

-		sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP;

-		sv_player->v.teleport_time = 0;

-	}

-	sv_player->v.velocity[0] = sv_player->v.movedir[0];

-	sv_player->v.velocity[1] = sv_player->v.movedir[1];

-}

-

-

-/*

-===================

-SV_AirMove

-

-===================

-*/

-void SV_AirMove (void)

-{

-	int			i;

-	vec3_t		wishvel;

-	float		fmove, smove;

-

-	AngleVectors (sv_player->v.angles, forward, right, up);

-

-	fmove = cmd.forwardmove;

-	smove = cmd.sidemove;

-	

-// hack to not let you back into teleporter

-	if (sv.time < sv_player->v.teleport_time && fmove < 0)

-		fmove = 0;

-		

-	for (i=0 ; i<3 ; i++)

-		wishvel[i] = forward[i]*fmove + right[i]*smove;

-

-	if ( (int)sv_player->v.movetype != MOVETYPE_WALK)

-		wishvel[2] = cmd.upmove;

-	else

-		wishvel[2] = 0;

-

-	VectorCopy (wishvel, wishdir);

-	wishspeed = VectorNormalize(wishdir);

-	if (wishspeed > sv_maxspeed.value)

-	{

-		VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);

-		wishspeed = sv_maxspeed.value;

-	}

-	

-	if ( sv_player->v.movetype == MOVETYPE_NOCLIP)

-	{	// noclip

-		VectorCopy (wishvel, velocity);

-	}

-	else if ( onground )

-	{

-		SV_UserFriction ();

-		SV_Accelerate ();

-	}

-	else

-	{	// not on ground, so little effect on velocity

-		SV_AirAccelerate (wishvel);

-	}		

-}

-

-/*

-===================

-SV_ClientThink

-

-the move fields specify an intended velocity in pix/sec

-the angle fields specify an exact angular motion in degrees

-===================

-*/

-void SV_ClientThink (void)

-{

-	vec3_t		v_angle;

-

-	if (sv_player->v.movetype == MOVETYPE_NONE)

-		return;

-	

-	onground = (int)sv_player->v.flags & FL_ONGROUND;

-

-	origin = sv_player->v.origin;

-	velocity = sv_player->v.velocity;

-

-	DropPunchAngle ();

-	

-//

-// if dead, behave differently

-//

-	if (sv_player->v.health <= 0)

-		return;

-

-//

-// angles

-// show 1/3 the pitch angle and all the roll angle

-	cmd = host_client->cmd;

-	angles = sv_player->v.angles;

-	

-	VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle);

-	angles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;

-	if (!sv_player->v.fixangle)

-	{

-		angles[PITCH] = -v_angle[PITCH]/3;

-		angles[YAW] = v_angle[YAW];

-	}

-

-	if ( (int)sv_player->v.flags & FL_WATERJUMP )

-	{

-		SV_WaterJump ();

-		return;

-	}

-//

-// walk

-//

-	if ( (sv_player->v.waterlevel >= 2)

-	&& (sv_player->v.movetype != MOVETYPE_NOCLIP) )

-	{

-		SV_WaterMove ();

-		return;

-	}

-

-	SV_AirMove ();	

-}

-

-

-/*

-===================

-SV_ReadClientMove

-===================

-*/

-void SV_ReadClientMove (usercmd_t *move)

-{

-	int		i;

-	vec3_t	angle;

-	int		bits;

-	

-// read ping time

-	host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]

-		= sv.time - MSG_ReadFloat ();

-	host_client->num_pings++;

-

-// read current angles	

-	for (i=0 ; i<3 ; i++)

-		angle[i] = MSG_ReadAngle ();

-

-	VectorCopy (angle, host_client->edict->v.v_angle);

-		

-// read movement

-	move->forwardmove = MSG_ReadShort ();

-	move->sidemove = MSG_ReadShort ();

-	move->upmove = MSG_ReadShort ();

-	

-// read buttons

-	bits = MSG_ReadByte ();

-	host_client->edict->v.button0 = bits & 1;

-	host_client->edict->v.button2 = (bits & 2)>>1;

-

-	i = MSG_ReadByte ();

-	if (i)

-		host_client->edict->v.impulse = i;

-

-#ifdef QUAKE2

-// read light level

-	host_client->edict->v.light_level = MSG_ReadByte ();

-#endif

-}

-

-/*

-===================

-SV_ReadClientMessage

-

-Returns false if the client should be killed

-===================

-*/

-qboolean SV_ReadClientMessage (void)

-{

-	int		ret;

-	int		cmd;

-	char		*s;

-	

-	do

-	{

-nextmsg:

-		ret = NET_GetMessage (host_client->netconnection);

-		if (ret == -1)

-		{

-			Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");

-			return false;

-		}

-		if (!ret)

-			return true;

-					

-		MSG_BeginReading ();

-		

-		while (1)

-		{

-			if (!host_client->active)

-				return false;	// a command caused an error

-

-			if (msg_badread)

-			{

-				Sys_Printf ("SV_ReadClientMessage: badread\n");

-				return false;

-			}	

-	

-			cmd = MSG_ReadChar ();

-			

-			switch (cmd)

-			{

-			case -1:

-				goto nextmsg;		// end of message

-				

-			default:

-				Sys_Printf ("SV_ReadClientMessage: unknown command char\n");

-				return false;

-							

-			case clc_nop:

-//				Sys_Printf ("clc_nop\n");

-				break;

-				

-			case clc_stringcmd:	

-				s = MSG_ReadString ();

-				if (host_client->privileged)

-					ret = 2;

-				else

-					ret = 0;

-				if (Q_strncasecmp(s, "status", 6) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "god", 3) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "notarget", 8) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "fly", 3) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "name", 4) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "noclip", 6) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "say", 3) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "say_team", 8) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "tell", 4) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "color", 5) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "kill", 4) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "pause", 5) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "spawn", 5) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "begin", 5) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "prespawn", 8) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "kick", 4) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "ping", 4) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "give", 4) == 0)

-					ret = 1;

-				else if (Q_strncasecmp(s, "ban", 3) == 0)

-					ret = 1;

-				if (ret == 2)

-					Cbuf_InsertText (s);

-				else if (ret == 1)

-					Cmd_ExecuteString (s, src_client);

-				else

-					Con_DPrintf("%s tried to %s\n", host_client->name, s);

-				break;

-				

-			case clc_disconnect:

-//				Sys_Printf ("SV_ReadClientMessage: client disconnected\n");

-				return false;

-			

-			case clc_move:

-				SV_ReadClientMove (&host_client->cmd);

-				break;

-			}

-		}

-	} while (ret == 1);

-	

-	return true;

-}

-

-

-/*

-==================

-SV_RunClients

-==================

-*/

-void SV_RunClients (void)

-{

-	int				i;

-	

-	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)

-	{

-		if (!host_client->active)

-			continue;

-	

-		sv_player = host_client->edict;

-

-		if (!SV_ReadClientMessage ())

-		{

-			SV_DropClient (false);	// client misbehaved...

-			continue;

-		}

-

-		if (!host_client->spawned)

-		{

-		// clear client movement until a new packet is received

-			memset (&host_client->cmd, 0, sizeof(host_client->cmd));

-			continue;

-		}

-

-// always pause in single player if in console or menus

-		if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )

-			SV_ClientThink ();

-	}

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// sv_user.c -- server code for moving users
+
+#include "quakedef.h"
+
+edict_t	*sv_player;
+
+extern	cvar_t	sv_friction;
+cvar_t	sv_edgefriction = CVAR2("edgefriction", "2");
+extern	cvar_t	sv_stopspeed;
+
+static	vec3_t		forward, right, up;
+
+vec3_t	wishdir;
+float	wishspeed;
+
+// world
+float	*angles;
+float	*origin;
+float	*velocity;
+
+qboolean	onground;
+
+usercmd_t	cmd;
+
+cvar_t	sv_idealpitchscale = CVAR2("sv_idealpitchscale","0.8");
+
+
+/*
+===============
+SV_SetIdealPitch
+===============
+*/
+#define	MAX_FORWARD	6
+void SV_SetIdealPitch (void)
+{
+	float	angleval, sinval, cosval;
+	trace_t	tr;
+	vec3_t	top, bottom;
+	float	z[MAX_FORWARD];
+	int		i, j;
+	int		step, dir, steps;
+
+	if (!((int)sv_player->u.v.flags & FL_ONGROUND))
+		return;
+		
+	angleval = sv_player->u.v.angles[YAW] * M_PI*2 / 360;
+	sinval = sin(angleval);
+	cosval = cos(angleval);
+
+	for (i=0 ; i<MAX_FORWARD ; i++)
+	{
+		top[0] = sv_player->u.v.origin[0] + cosval*(i+3)*12;
+		top[1] = sv_player->u.v.origin[1] + sinval*(i+3)*12;
+		top[2] = sv_player->u.v.origin[2] + sv_player->u.v.view_ofs[2];
+		
+		bottom[0] = top[0];
+		bottom[1] = top[1];
+		bottom[2] = top[2] - 160;
+		
+		tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player);
+		if (tr.allsolid)
+			return;	// looking at a wall, leave ideal the way is was
+
+		if (tr.fraction == 1)
+			return;	// near a dropoff
+		
+		z[i] = top[2] + tr.fraction*(bottom[2]-top[2]);
+	}
+	
+	dir = 0;
+	steps = 0;
+	for (j=1 ; j<i ; j++)
+	{
+		step = (int) (z[j] - z[j-1]);
+		if (step > -ON_EPSILON && step < ON_EPSILON)
+			continue;
+
+		if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) )
+			return;		// mixed changes
+
+		steps++;	
+		dir = step;
+	}
+	
+	if (!dir)
+	{
+		sv_player->u.v.idealpitch = 0;
+		return;
+	}
+	
+	if (steps < 2)
+		return;
+	sv_player->u.v.idealpitch = -dir * sv_idealpitchscale.value;
+}
+
+
+/*
+==================
+SV_UserFriction
+
+==================
+*/
+void SV_UserFriction (void)
+{
+	float	*vel;
+	float	speed, newspeed, control;
+	vec3_t	start, stop;
+	float	friction;
+	trace_t	trace;
+	
+	vel = velocity;
+	
+	speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
+	if (!speed)
+		return;
+
+// if the leading edge is over a dropoff, increase friction
+	start[0] = stop[0] = origin[0] + vel[0]/speed*16;
+	start[1] = stop[1] = origin[1] + vel[1]/speed*16;
+	start[2] = origin[2] + sv_player->u.v.mins[2];
+	stop[2] = start[2] - 34;
+
+	trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player);
+
+	if (trace.fraction == 1.0)
+		friction = sv_friction.value*sv_edgefriction.value;
+	else
+		friction = sv_friction.value;
+
+// apply friction	
+	control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
+	newspeed = speed - host_frametime*control*friction;
+	
+	if (newspeed < 0)
+		newspeed = 0;
+	newspeed /= speed;
+
+	vel[0] = vel[0] * newspeed;
+	vel[1] = vel[1] * newspeed;
+	vel[2] = vel[2] * newspeed;
+}
+
+/*
+==============
+SV_Accelerate
+==============
+*/
+cvar_t	sv_maxspeed = CVAR4("sv_maxspeed", "320", false, true);
+cvar_t	sv_accelerate = CVAR2("sv_accelerate", "10");
+#if 0
+void SV_Accelerate (vec3_t wishvel)
+{
+	int			i;
+	float		addspeed, accelspeed;
+	vec3_t		pushvec;
+
+	if (wishspeed == 0)
+		return;
+
+	VectorSubtract (wishvel, velocity, pushvec);
+	addspeed = VectorNormalize (pushvec);
+
+	accelspeed = sv_accelerate.value*host_frametime*addspeed;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		velocity[i] += accelspeed*pushvec[i];	
+}
+#endif
+void SV_Accelerate (void)
+{
+	int			i;
+	float		addspeed, accelspeed, currentspeed;
+
+	currentspeed = DotProduct (velocity, wishdir);
+	addspeed = wishspeed - currentspeed;
+	if (addspeed <= 0)
+		return;
+	accelspeed = sv_accelerate.value*host_frametime*wishspeed;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		velocity[i] += accelspeed*wishdir[i];	
+}
+
+void SV_AirAccelerate (vec3_t wishveloc)
+{
+	int			i;
+	float		addspeed, wishspd, accelspeed, currentspeed;
+		
+	wishspd = VectorNormalize (wishveloc);
+	if (wishspd > 30)
+		wishspd = 30;
+	currentspeed = DotProduct (velocity, wishveloc);
+	addspeed = wishspd - currentspeed;
+	if (addspeed <= 0)
+		return;
+//	accelspeed = sv_accelerate.value * host_frametime;
+	accelspeed = sv_accelerate.value*wishspeed * host_frametime;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+	
+	for (i=0 ; i<3 ; i++)
+		velocity[i] += accelspeed*wishveloc[i];	
+}
+
+
+void DropPunchAngle (void)
+{
+	float	len;
+	
+	len = VectorNormalize (sv_player->u.v.punchangle);
+	
+	len -= 10*host_frametime;
+	if (len < 0)
+		len = 0;
+	VectorScale (sv_player->u.v.punchangle, len, sv_player->u.v.punchangle);
+}
+
+/*
+===================
+SV_WaterMove
+
+===================
+*/
+void SV_WaterMove (void)
+{
+	int		i;
+	vec3_t	wishvel;
+	float	speed, newspeed, wishspeed, addspeed, accelspeed;
+
+//
+// user intentions
+//
+	AngleVectors (sv_player->u.v.v_angle, forward, right, up);
+
+	for (i=0 ; i<3 ; i++)
+		wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
+
+	if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)
+		wishvel[2] -= 60;		// drift towards bottom
+	else
+		wishvel[2] += cmd.upmove;
+
+	wishspeed = Length(wishvel);
+	if (wishspeed > sv_maxspeed.value)
+	{
+		VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
+		wishspeed = sv_maxspeed.value;
+	}
+	wishspeed *= 0.7;
+
+//
+// water friction
+//
+	speed = Length (velocity);
+	if (speed)
+	{
+		newspeed = speed - host_frametime * speed * sv_friction.value;
+		if (newspeed < 0)
+			newspeed = 0;	
+		VectorScale (velocity, newspeed/speed, velocity);
+	}
+	else
+		newspeed = 0;
+	
+//
+// water acceleration
+//
+	if (!wishspeed)
+		return;
+
+	addspeed = wishspeed - newspeed;
+	if (addspeed <= 0)
+		return;
+
+	VectorNormalize (wishvel);
+	accelspeed = sv_accelerate.value * wishspeed * host_frametime;
+	if (accelspeed > addspeed)
+		accelspeed = addspeed;
+
+	for (i=0 ; i<3 ; i++)
+		velocity[i] += accelspeed * wishvel[i];
+}
+
+void SV_WaterJump (void)
+{
+	if (sv.time > sv_player->u.v.teleport_time
+	|| !sv_player->u.v.waterlevel)
+	{
+		sv_player->u.v.flags = (int)sv_player->u.v.flags & ~FL_WATERJUMP;
+		sv_player->u.v.teleport_time = 0;
+	}
+	sv_player->u.v.velocity[0] = sv_player->u.v.movedir[0];
+	sv_player->u.v.velocity[1] = sv_player->u.v.movedir[1];
+}
+
+
+/*
+===================
+SV_AirMove
+
+===================
+*/
+void SV_AirMove (void)
+{
+	int			i;
+	vec3_t		wishvel;
+	float		fmove, smove;
+
+	AngleVectors (sv_player->u.v.angles, forward, right, up);
+
+	fmove = cmd.forwardmove;
+	smove = cmd.sidemove;
+	
+// hack to not let you back into teleporter
+	if (sv.time < sv_player->u.v.teleport_time && fmove < 0)
+		fmove = 0;
+		
+	for (i=0 ; i<3 ; i++)
+		wishvel[i] = forward[i]*fmove + right[i]*smove;
+
+	if ( (int)sv_player->u.v.movetype != MOVETYPE_WALK)
+		wishvel[2] = cmd.upmove;
+	else
+		wishvel[2] = 0;
+
+	VectorCopy (wishvel, wishdir);
+	wishspeed = VectorNormalize(wishdir);
+	if (wishspeed > sv_maxspeed.value)
+	{
+		VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
+		wishspeed = sv_maxspeed.value;
+	}
+	
+	if ( sv_player->u.v.movetype == MOVETYPE_NOCLIP)
+	{	// noclip
+		VectorCopy (wishvel, velocity);
+	}
+	else if ( onground )
+	{
+		SV_UserFriction ();
+		SV_Accelerate ();
+	}
+	else
+	{	// not on ground, so little effect on velocity
+		SV_AirAccelerate (wishvel);
+	}		
+}
+
+/*
+===================
+SV_ClientThink
+
+the move fields specify an intended velocity in pix/sec
+the angle fields specify an exact angular motion in degrees
+===================
+*/
+void SV_ClientThink (void)
+{
+	vec3_t		v_angle;
+
+	if (sv_player->u.v.movetype == MOVETYPE_NONE)
+		return;
+	
+	onground = (int)sv_player->u.v.flags & FL_ONGROUND;
+
+	origin = sv_player->u.v.origin;
+	velocity = sv_player->u.v.velocity;
+
+	DropPunchAngle ();
+	
+//
+// if dead, behave differently
+//
+	if (sv_player->u.v.health <= 0)
+		return;
+
+//
+// angles
+// show 1/3 the pitch angle and all the roll angle
+	cmd = host_client->cmd;
+	angles = sv_player->u.v.angles;
+	
+	VectorAdd (sv_player->u.v.v_angle, sv_player->u.v.punchangle, v_angle);
+	angles[ROLL] = V_CalcRoll (sv_player->u.v.angles, sv_player->u.v.velocity)*4;
+	if (!sv_player->u.v.fixangle)
+	{
+		angles[PITCH] = -v_angle[PITCH]/3;
+		angles[YAW] = v_angle[YAW];
+	}
+
+	if ( (int)sv_player->u.v.flags & FL_WATERJUMP )
+	{
+		SV_WaterJump ();
+		return;
+	}
+//
+// walk
+//
+	if ( (sv_player->u.v.waterlevel >= 2)
+	&& (sv_player->u.v.movetype != MOVETYPE_NOCLIP) )
+	{
+		SV_WaterMove ();
+		return;
+	}
+
+	SV_AirMove ();	
+}
+
+
+/*
+===================
+SV_ReadClientMove
+===================
+*/
+void SV_ReadClientMove (usercmd_t *move)
+{
+	int		i;
+	vec3_t	angle;
+	int		bits;
+	
+// read ping time
+	host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
+		= sv.time - MSG_ReadFloat ();
+	host_client->num_pings++;
+
+// read current angles	
+	for (i=0 ; i<3 ; i++)
+		angle[i] = MSG_ReadAngle ();
+
+	VectorCopy (angle, host_client->edict->u.v.v_angle);
+		
+// read movement
+	move->forwardmove = MSG_ReadShort ();
+	move->sidemove = MSG_ReadShort ();
+	move->upmove = MSG_ReadShort ();
+	
+// read buttons
+	bits = MSG_ReadByte ();
+	host_client->edict->u.v.button0 = bits & 1;
+	host_client->edict->u.v.button2 = (bits & 2)>>1;
+
+	i = MSG_ReadByte ();
+	if (i)
+		host_client->edict->u.v.impulse = i;
+
+#ifdef QUAKE2
+// read light level
+	host_client->edict->u.v.light_level = MSG_ReadByte ();
+#endif
+}
+
+/*
+===================
+SV_ReadClientMessage
+
+Returns false if the client should be killed
+===================
+*/
+qboolean SV_ReadClientMessage (void)
+{
+	int		ret;
+	int		cmd;
+	char		*s;
+	
+	do
+	{
+nextmsg:
+		ret = NET_GetMessage (host_client->netconnection);
+		if (ret == -1)
+		{
+			Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
+			return false;
+		}
+		if (!ret)
+			return true;
+					
+		MSG_BeginReading ();
+		
+		while (1)
+		{
+			if (!host_client->active)
+				return false;	// a command caused an error
+
+			if (msg_badread)
+			{
+				Sys_Printf ("SV_ReadClientMessage: badread\n");
+				return false;
+			}	
+	
+			cmd = MSG_ReadChar ();
+			
+			switch (cmd)
+			{
+			case -1:
+				goto nextmsg;		// end of message
+				
+			default:
+				Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
+				return false;
+							
+			case clc_nop:
+//				Sys_Printf ("clc_nop\n");
+				break;
+				
+			case clc_stringcmd:	
+				s = MSG_ReadString ();
+				if (host_client->privileged)
+					ret = 2;
+				else
+					ret = 0;
+				if (Q_strncasecmp(s, "status", 6) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "god", 3) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "notarget", 8) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "fly", 3) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "name", 4) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "noclip", 6) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "say", 3) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "say_team", 8) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "tell", 4) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "color", 5) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "kill", 4) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "pause", 5) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "spawn", 5) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "begin", 5) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "prespawn", 8) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "kick", 4) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "ping", 4) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "give", 4) == 0)
+					ret = 1;
+				else if (Q_strncasecmp(s, "ban", 3) == 0)
+					ret = 1;
+				if (ret == 2)
+					Cbuf_InsertText (s);
+				else if (ret == 1)
+					Cmd_ExecuteString (s, src_client);
+				else
+					Con_DPrintf("%s tried to %s\n", host_client->name, s);
+				break;
+				
+			case clc_disconnect:
+//				Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
+				return false;
+			
+			case clc_move:
+				SV_ReadClientMove (&host_client->cmd);
+				break;
+			}
+		}
+	} while (ret == 1);
+	
+	return true;
+}
+
+
+/*
+==================
+SV_RunClients
+==================
+*/
+void SV_RunClients (void)
+{
+	int				i;
+	
+	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
+	{
+		if (!host_client->active)
+			continue;
+	
+		sv_player = host_client->edict;
+
+		if (!SV_ReadClientMessage ())
+		{
+			SV_DropClient (false);	// client misbehaved...
+			continue;
+		}
+
+		if (!host_client->spawned)
+		{
+		// clear client movement until a new packet is received
+			memset (&host_client->cmd, 0, sizeof(host_client->cmd));
+			continue;
+		}
+
+// always pause in single player if in console or menus
+		if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
+			SV_ClientThink ();
+	}
+}
+
diff --git a/quake/src/WinQuake/sys.h b/quake/src/WinQuake/sys.h
index b3dddae..23214fe 100644
--- a/quake/src/WinQuake/sys.h
+++ b/quake/src/WinQuake/sys.h
@@ -1,71 +1,71 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// sys.h -- non-portable functions

-

-//

-// file IO

-//

-

-// returns the file size

-// return -1 if file is not present

-// the file should be in BINARY mode for stupid OSs that care

-int Sys_FileOpenRead (char *path, int *hndl);

-

-int Sys_FileOpenWrite (char *path);

-void Sys_FileClose (int handle);

-void Sys_FileSeek (int handle, int position);

-int Sys_FileRead (int handle, void *dest, int count);

-int Sys_FileWrite (int handle, void *data, int count);

-int	Sys_FileTime (char *path);

-void Sys_mkdir (char *path);

-

-//

-// memory protection

-//

-void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);

-

-//

-// system IO

-//

-void Sys_DebugLog(char *file, char *fmt, ...);

-

-void Sys_Error (char *error, ...);

-// an error will cause the entire program to exit

-

-void Sys_Printf (char *fmt, ...);

-// send text to the console

-

-void Sys_Quit (void);

-

-double Sys_FloatTime (void);

-

-char *Sys_ConsoleInput (void);

-

-void Sys_Sleep (void);

-// called to yield for a little bit so as

-// not to hog cpu when paused or debugging

-

-void Sys_SendKeyEvents (void);

-// Perform Key_Event () callbacks until the input que is empty

-

-void Sys_LowFPPrecision (void);

-void Sys_HighFPPrecision (void);

-void Sys_SetFPCW (void);

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// sys.h -- non-portable functions
+
+//
+// file IO
+//
+
+// returns the file size
+// return -1 if file is not present
+// the file should be in BINARY mode for stupid OSs that care
+int Sys_FileOpenRead (const char *path, int *hndl);
+
+int Sys_FileOpenWrite (const char *path);
+void Sys_FileClose (int handle);
+void Sys_FileSeek (int handle, int position);
+int Sys_FileRead (int handle, void *dest, int count);
+int Sys_FileWrite (int handle, const void *data, int count);
+int	Sys_FileTime (const char *path);
+void Sys_mkdir (const char *path);
+
+//
+// memory protection
+//
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
+
+//
+// system IO
+//
+void Sys_DebugLog(const char *file, const char *fmt, ...);
+
+void Sys_Error (const char *error, ...);
+// an error will cause the entire program to exit
+
+void Sys_Printf (const char *fmt, ...);
+// send text to the console
+
+void Sys_Quit (void);
+
+double Sys_FloatTime (void);
+
+char *Sys_ConsoleInput (void);
+
+void Sys_Sleep (void);
+// called to yield for a little bit so as
+// not to hog cpu when paused or debugging
+
+void Sys_SendKeyEvents (void);
+// Perform Key_Event () callbacks until the input que is empty
+
+void Sys_LowFPPrecision (void);
+void Sys_HighFPPrecision (void);
+void Sys_SetFPCW (void);
+
diff --git a/quake/src/WinQuake/sys_android.cpp b/quake/src/WinQuake/sys_android.cpp
new file mode 100755
index 0000000..aab0d4e
--- /dev/null
+++ b/quake/src/WinQuake/sys_android.cpp
@@ -0,0 +1,649 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+// System functions for Android OS.
+// Based on sys_linux.c
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+// #include <sys/ipc.h>
+// #include <sys/shm.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <utils/Log.h>
+#include "quakedef.h"
+
+qboolean			isDedicated;
+
+int noconinput = 0;
+int nostdout = 0;
+
+// Look for data on either the sdcard or the internal data store.
+// (We look at the sdcard first
+
+static const char *basedir1 = "/sdcard/data/quake";
+static const char *basedir2 = "/data/quake";
+
+static const char *cachedir = "/tmp";
+
+cvar_t  sys_linerefresh = CVAR2("sys_linerefresh","0");// set for entity display
+
+// =======================================================================
+// General routines
+// =======================================================================
+
+void Sys_DebugNumber(int y, int val)
+{
+}
+
+/*
+void Sys_Printf (char *fmt, ...)
+{
+  va_list		argptr;
+  char		text[1024];
+
+  va_start (argptr,fmt);
+  vsprintf (text,fmt,argptr);
+  va_end (argptr);
+  fprintf(stderr, "%s", text);
+
+  Con_Print (text);
+}
+
+void Sys_Printf (char *fmt, ...)
+{
+
+    va_list     argptr;
+    char        text[1024], *t_p;
+    int         l, r;
+
+    if (nostdout)
+        return;
+
+    va_start (argptr,fmt);
+    vsprintf (text,fmt,argptr);
+    va_end (argptr);
+
+    l = strlen(text);
+    t_p = text;
+
+// make sure everything goes through, even though we are non-blocking
+    while (l)
+    {
+        r = write (1, text, l);
+        if (r != l)
+            sleep (0);
+        if (r > 0)
+        {
+            t_p += r;
+            l -= r;
+        }
+    }
+
+}
+*/
+
+#define USE_PMPEVENT
+
+void Sys_Printf (const char *fmt, ...)
+{
+  va_list		argptr;
+  char		text[2048];
+  unsigned char		*p;
+
+  va_start (argptr,fmt);
+  vsnprintf (text, sizeof(text), fmt,argptr);
+  va_end (argptr);
+
+  text[sizeof(text)-1] = 0;
+  LOGI("%s", text);
+
+#ifdef USE_PMPEVENT
+    PMPEVENT(("%s", text));
+#else
+    if (nostdout)
+        return;
+
+  for (p = (unsigned char *)text; *p; p++)
+    if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
+      printf("[%02x]", *p);
+    else
+      putc(*p, stdout);
+#endif
+}
+
+qboolean soft_quit;
+
+void Sys_Quit (void)
+{
+  Host_Shutdown();
+#ifdef USE_PMPEVENT
+  PMPERROR(("Sys_Quit - exiting."));
+#else
+  printf("Sys_Quit - exiting.\n");
+#endif
+    // fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
+  if (soft_quit) {
+    return;
+  }
+    exit(0);
+}
+
+void Sys_Init(void)
+{
+
+}
+
+void Sys_Error (const char *error, ...)
+{
+    va_list     argptr;
+    char        string[1024];
+
+// change stdin to non blocking
+    // fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
+
+    va_start (argptr,error);
+    vsprintf (string,error,argptr);
+    va_end (argptr);
+#ifdef USE_PMPEVENT
+  PMPERROR(("Error: %s\n", string));
+#else
+  fprintf(stderr, "Error: %s\n", string);
+#endif
+  Host_Shutdown ();
+#ifdef USE_PMPEVENT
+  PMPERROR(("Sys_Error - exiting."));
+#else
+  printf("Sys_Error - exiting.\n");
+#endif
+  exit (1);
+
+}
+
+void Sys_Warn (const char *warning, ...)
+{
+    va_list     argptr;
+    char        string[1024];
+
+    va_start (argptr,warning);
+    vsprintf (string,warning,argptr);
+    va_end (argptr);
+#ifdef USE_PMPEVENT
+  PMPWARNING(("Warning: %s", string));
+#else
+  fprintf(stderr, "Warning: %s\n", string);
+#endif
+}
+
+/*
+============
+Sys_FileTime
+
+returns -1 if not present
+============
+*/
+int	Sys_FileTime (const char *path)
+{
+  struct	stat	buf;
+
+  if (stat (path,&buf) == -1)
+    return -1;
+
+  return buf.st_mtime;
+}
+
+
+void Sys_mkdir (const char *path)
+{
+    mkdir (path, 0777);
+}
+
+int Sys_FileOpenRead (const char *path, int *handle)
+{
+  int	h;
+  struct stat	fileinfo;
+
+
+  h = open (path, O_RDONLY, 0666);
+  *handle = h;
+  if (h == -1)
+    return -1;
+
+  if (fstat (h,&fileinfo) == -1)
+    Sys_Error ("Error fstating %s", path);
+
+  return fileinfo.st_size;
+}
+
+int Sys_FileOpenWrite (const char *path)
+{
+  int     handle;
+
+  umask (0);
+
+  handle = open(path,O_RDWR | O_CREAT | O_TRUNC
+  , 0666);
+
+  if (handle == -1)
+    Sys_Error ("Error opening %s: %s", path,strerror(errno));
+
+  return handle;
+}
+
+int Sys_FileWrite (int handle, const void *src, int count)
+{
+  return write (handle, src, count);
+}
+
+void Sys_FileClose (int handle)
+{
+  close (handle);
+}
+
+void Sys_FileSeek (int handle, int position)
+{
+  lseek (handle, position, SEEK_SET);
+}
+
+int Sys_FileRead (int handle, void *dest, int count)
+{
+    return read (handle, dest, count);
+}
+
+void Sys_DebugLog(const char *file, char *fmt, ...)
+{
+    va_list argptr;
+    static char data[1024];
+    int fd;
+
+    va_start(argptr, fmt);
+    vsprintf(data, fmt, argptr);
+    va_end(argptr);
+//    fd = open(file, O_WRONLY | O_BINARY | O_CREAT | O_APPEND, 0666);
+    fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
+    write(fd, data, strlen(data));
+    close(fd);
+}
+
+void Sys_EditFile(const char *filename)
+{
+
+  char cmd[256];
+  char *term;
+  const char *editor;
+
+  term = getenv("TERM");
+  if (term && !strcmp(term, "xterm"))
+  {
+    editor = getenv("VISUAL");
+    if (!editor)
+      editor = getenv("EDITOR");
+    if (!editor)
+      editor = getenv("EDIT");
+    if (!editor)
+      editor = "vi";
+    sprintf(cmd, "xterm -e %s %s", editor, filename);
+    system(cmd);
+  }
+
+}
+
+double Sys_FloatTime (void)
+{
+    struct timeval tp;
+    struct timezone tzp;
+    static int      secbase;
+
+    gettimeofday(&tp, &tzp);
+
+    if (!secbase)
+    {
+        secbase = tp.tv_sec;
+        return tp.tv_usec/1000000.0;
+    }
+
+    return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
+}
+
+// =======================================================================
+// Sleeps for microseconds
+// =======================================================================
+
+static volatile int oktogo;
+
+void alarm_handler(int x)
+{
+  oktogo=1;
+}
+
+void Sys_LineRefresh(void)
+{
+}
+
+void floating_point_exception_handler(int whatever)
+{
+//	Sys_Warn("floating point exception\n");
+  signal(SIGFPE, floating_point_exception_handler);
+}
+
+char *Sys_ConsoleInput(void)
+{
+#if 0
+    static char text[256];
+    int     len;
+
+  if (cls.state == ca_dedicated) {
+    len = read (0, text, sizeof(text));
+    if (len < 1)
+      return NULL;
+    text[len-1] = 0;    // rip off the /n and terminate
+
+    return text;
+  }
+#endif
+  return NULL;
+}
+
+#if !id386
+void Sys_HighFPPrecision (void)
+{
+}
+
+void Sys_LowFPPrecision (void)
+{
+}
+#endif
+
+int		skipframes;
+
+// The following APIs are called from the Java activity
+
+double g_oldtime;
+
+extern int scr_width;
+extern int scr_height;
+
+qboolean direxists(const char* path)
+{
+  struct stat sb;
+  if(stat(path, &sb))
+  {
+    return 0;	// error
+  }
+  if(sb.st_mode & S_IFDIR)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+// Remove all files in path. Recurses into subdirectories
+
+void rmDir(const char* path) {
+  DIR* dir = opendir(path);
+  if(!dir) {
+    return;
+  }
+  struct dirent * dp;
+  while((dp = readdir(dir)) != NULL) {
+    const char* name = dp->d_name;
+    if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+      continue;
+    }
+    char filePath[1024];
+    if ((int) (sizeof(filePath)-1) < snprintf(filePath, sizeof(filePath), "%s/%s", path, name)) {
+      continue; // buffer overflow
+    }
+    if(direxists(filePath)) {
+      rmDir(filePath);
+    }
+    else {
+      unlink(filePath);
+    }
+  }
+  closedir(dir);
+  rmdir(path);
+}
+
+// Increment this number whenever the data format of any of the files stored in glquake changes:
+
+typedef unsigned long GLCacheVersion;
+
+static const GLCacheVersion kCurrentCacheVersion = 0x3a914000; // The numbers mean nothing special
+
+// #define FORCE_INVALIDATE_CACHE // Useful for testing
+
+#define GLQUAKE_RELPATH "/id1/glquake"
+void CheckGLCacheVersion(const char* baseDir)
+{
+  char cachePath[1024];
+  if ((int) (sizeof(cachePath)-1) < snprintf(cachePath, sizeof(cachePath), "%s" GLQUAKE_RELPATH "/cacheversion", baseDir)) {
+    return; // buffer overflow
+  }
+  bool validCache = false;
+  {
+    GLCacheVersion vernum = 0;
+    FILE* f = fopen(cachePath, "rb");
+    if (f) {
+      if (1 == fread(&vernum, sizeof(vernum), 1, f)) {
+        if (vernum == kCurrentCacheVersion) {
+          validCache = true;
+        }
+      }
+      fclose(f);
+    }
+  }
+
+#ifdef FORCE_INVALIDATE_CACHE
+  validCache = false;
+#endif
+
+  if(!validCache) {
+    PMPLOG(("Invalidating glquake cache."));
+    char cacheDirPath[1024];
+    if ( (int)(sizeof(cacheDirPath)-1) < snprintf(cacheDirPath, sizeof(cachePath), "%s" GLQUAKE_RELPATH, baseDir)) {
+      return; // Ran out ot memory
+    }
+    rmDir(cacheDirPath);
+    Sys_mkdir(cacheDirPath);
+    FILE* f = fopen(cachePath, "wb");
+    GLCacheVersion vernum = kCurrentCacheVersion;
+    fwrite(&vernum, sizeof(vernum), 1, f);
+    fclose(f);
+  }
+}
+
+static int gArgc;
+static char** gArgv;
+
+void AndroidInitArgs(int argc, char** argv) {
+    gArgc = argc;
+    gArgv = argv;
+}
+
+static qboolean gDoubleInitializeGuard;
+static qboolean gInitialized;
+void GL_ReInit();
+
+bool AndroidInit()
+{
+  PMPLOG(("AndroidInit"));
+
+  PMPLOG(("This function was compiled on " __DATE__ " at " __TIME__));
+
+  if (gDoubleInitializeGuard && gInitialized)
+  {
+    GL_ReInit();
+  }
+
+  gDoubleInitializeGuard = true;
+  return true;
+}
+
+
+// Note: Needs a valid OpenGL context
+
+void AndroidInit2(int width, int height)
+{
+  PMPLOG(("AndroidInit2 %d,%d", width, height));
+
+  gInitialized = true;
+  PMPBEGIN(("AndroidInit2"));
+  quakeparms_t parms;
+  int j;
+  int c = 0;
+  const char* v[] = {"quake", (char*) 0};
+
+  scr_width = width;
+  scr_height = height;
+
+//	static char cwd[1024];
+
+//	signal(SIGFPE, floating_point_exception_handler);
+//  signal(SIGFPE, SIG_IGN);
+
+  memset(&parms, 0, sizeof(parms));
+
+  if (gArgc) {
+      COM_InitArgv(gArgc, (const char**) gArgv);
+  }
+  else {
+      COM_InitArgv(c, (const char**) v);
+  }
+
+  parms.argc = com_argc;
+  parms.argv = com_argv;
+
+  parms.memsize = 16*1024*1024;
+
+  j = COM_CheckParm("-mem");
+  if (j)
+    parms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
+  parms.membase = malloc (parms.memsize);
+
+  const char* basedir = basedir2;
+  if(direxists(basedir1))
+  {
+    basedir = basedir1;
+  }
+  else if(direxists(basedir2))
+  {
+    basedir = basedir2;
+  }
+  else
+  {
+    Sys_Error("Could not find data directories %s or %s", basedir1, basedir2);
+  }
+  parms.basedir = basedir;
+
+  CheckGLCacheVersion(basedir);
+
+// caching is disabled by default, use -cachedir to enable
+//	parms.cachedir = cachedir;
+
+#if 0 // FNDELAY not implemented
+  noconinput = COM_CheckParm("-noconinput");
+  if (!noconinput)
+    fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
+#endif
+
+  if (COM_CheckParm("-nostdout"))
+    nostdout = 1;
+
+  Sys_Init();
+
+    Host_Init(&parms);
+
+    g_oldtime = Sys_FloatTime ();
+  PMPEND(("AndroidInit2"));
+}
+
+static int currentFrame;
+frameTime fastestFrame;
+frameTime slowestFrame;
+
+void InitFrameTimes()
+{
+    currentFrame = 0;
+  fastestFrame.time = 1e6;
+  fastestFrame.frame = 0;
+  slowestFrame.time = -1;
+  slowestFrame.frame = 0;
+}
+
+static void UpdateFrameTimes(float time)
+{
+    if (currentFrame > 0) {
+
+    if (fastestFrame.time > time) {
+      fastestFrame.time = time;
+      fastestFrame.frame = currentFrame;
+    }
+    if (slowestFrame.time < time) {
+      slowestFrame.time = time;
+      slowestFrame.frame = currentFrame;
+    }
+  }
+  currentFrame++;
+}
+
+int AndroidStep(int width, int height)
+{
+  // PMPBEGIN(("AndroidStep"));
+  double time, newtime;
+
+  if(!gInitialized)
+    AndroidInit2(width, height);
+
+  scr_width = width;
+  scr_height = height;
+
+  // find time spent rendering last frame
+  newtime = Sys_FloatTime ();
+  time = newtime - g_oldtime;
+
+  UpdateFrameTimes(time);
+
+  Host_Frame(time);
+  g_oldtime = newtime;
+  // PMPEND(("AndroidStep"));
+  return key_dest == key_game;
+}
+
+extern void Host_Quit();
+void AndroidQuit() {
+  soft_quit = true;
+  Host_Quit();
+  soft_quit = false; // In case we live on after returning.
+}
diff --git a/quake/src/WinQuake/sys_dos.c b/quake/src/WinQuake/sys_dos.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/sys_dos.c
rename to quake/src/WinQuake/sys_dos.cpp
diff --git a/quake/src/WinQuake/sys_linux.c b/quake/src/WinQuake/sys_linux.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/sys_linux.c
rename to quake/src/WinQuake/sys_linux.cpp
diff --git a/quake/src/WinQuake/sys_null.c b/quake/src/WinQuake/sys_null.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/sys_null.c
rename to quake/src/WinQuake/sys_null.cpp
diff --git a/quake/src/WinQuake/sys_sun.c b/quake/src/WinQuake/sys_sun.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/sys_sun.c
rename to quake/src/WinQuake/sys_sun.cpp
diff --git a/quake/src/WinQuake/sys_win.c b/quake/src/WinQuake/sys_win.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/sys_win.c
rename to quake/src/WinQuake/sys_win.cpp
diff --git a/quake/src/WinQuake/sys_wind.c b/quake/src/WinQuake/sys_wind.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/sys_wind.c
rename to quake/src/WinQuake/sys_wind.cpp
diff --git a/quake/src/WinQuake/vid_dos.c b/quake/src/WinQuake/vid_dos.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_dos.c
rename to quake/src/WinQuake/vid_dos.cpp
diff --git a/quake/src/WinQuake/vid_ext.c b/quake/src/WinQuake/vid_ext.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_ext.c
rename to quake/src/WinQuake/vid_ext.cpp
diff --git a/quake/src/WinQuake/vid_null.c b/quake/src/WinQuake/vid_null.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_null.c
rename to quake/src/WinQuake/vid_null.cpp
diff --git a/quake/src/WinQuake/vid_sunx.c b/quake/src/WinQuake/vid_sunx.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_sunx.c
rename to quake/src/WinQuake/vid_sunx.cpp
diff --git a/quake/src/WinQuake/vid_sunxil.c b/quake/src/WinQuake/vid_sunxil.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_sunxil.c
rename to quake/src/WinQuake/vid_sunxil.cpp
diff --git a/quake/src/WinQuake/vid_svgalib.c b/quake/src/WinQuake/vid_svgalib.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_svgalib.c
rename to quake/src/WinQuake/vid_svgalib.cpp
diff --git a/quake/src/WinQuake/vid_vga.c b/quake/src/WinQuake/vid_vga.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_vga.c
rename to quake/src/WinQuake/vid_vga.cpp
diff --git a/quake/src/WinQuake/vid_win.c b/quake/src/WinQuake/vid_win.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_win.c
rename to quake/src/WinQuake/vid_win.cpp
diff --git a/quake/src/WinQuake/vid_x.c b/quake/src/WinQuake/vid_x.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vid_x.c
rename to quake/src/WinQuake/vid_x.cpp
diff --git a/quake/src/WinQuake/view.c b/quake/src/WinQuake/view.cpp
old mode 100644
new mode 100755
similarity index 91%
rename from quake/src/WinQuake/view.c
rename to quake/src/WinQuake/view.cpp
index 324d023..1c6c253
--- a/quake/src/WinQuake/view.c
+++ b/quake/src/WinQuake/view.cpp
@@ -1,1113 +1,1113 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// view.c -- player eye positioning

-

-#include "quakedef.h"

-#include "r_local.h"

-

-/*

-

-The view is allowed to move slightly from it's true position for bobbing,

-but if it exceeds 8 pixels linear distance (spherical, not box), the list of

-entities sent from the server may not include everything in the pvs, especially

-when crossing a water boudnary.

-

-*/

-

-cvar_t		lcd_x = {"lcd_x","0"};

-cvar_t		lcd_yaw = {"lcd_yaw","0"};

-

-cvar_t	scr_ofsx = {"scr_ofsx","0", false};

-cvar_t	scr_ofsy = {"scr_ofsy","0", false};

-cvar_t	scr_ofsz = {"scr_ofsz","0", false};

-

-cvar_t	cl_rollspeed = {"cl_rollspeed", "200"};

-cvar_t	cl_rollangle = {"cl_rollangle", "2.0"};

-

-cvar_t	cl_bob = {"cl_bob","0.02", false};

-cvar_t	cl_bobcycle = {"cl_bobcycle","0.6", false};

-cvar_t	cl_bobup = {"cl_bobup","0.5", false};

-

-cvar_t	v_kicktime = {"v_kicktime", "0.5", false};

-cvar_t	v_kickroll = {"v_kickroll", "0.6", false};

-cvar_t	v_kickpitch = {"v_kickpitch", "0.6", false};

-

-cvar_t	v_iyaw_cycle = {"v_iyaw_cycle", "2", false};

-cvar_t	v_iroll_cycle = {"v_iroll_cycle", "0.5", false};

-cvar_t	v_ipitch_cycle = {"v_ipitch_cycle", "1", false};

-cvar_t	v_iyaw_level = {"v_iyaw_level", "0.3", false};

-cvar_t	v_iroll_level = {"v_iroll_level", "0.1", false};

-cvar_t	v_ipitch_level = {"v_ipitch_level", "0.3", false};

-

-cvar_t	v_idlescale = {"v_idlescale", "0", false};

-

-cvar_t	crosshair = {"crosshair", "0", true};

-cvar_t	cl_crossx = {"cl_crossx", "0", false};

-cvar_t	cl_crossy = {"cl_crossy", "0", false};

-

-cvar_t	gl_cshiftpercent = {"gl_cshiftpercent", "100", false};

-

-float	v_dmg_time, v_dmg_roll, v_dmg_pitch;

-

-extern	int			in_forward, in_forward2, in_back;

-

-

-/*

-===============

-V_CalcRoll

-

-Used by view and sv_user

-===============

-*/

-vec3_t	forward, right, up;

-

-float V_CalcRoll (vec3_t angles, vec3_t velocity)

-{

-	float	sign;

-	float	side;

-	float	value;

-	

-	AngleVectors (angles, forward, right, up);

-	side = DotProduct (velocity, right);

-	sign = side < 0 ? -1 : 1;

-	side = fabs(side);

-	

-	value = cl_rollangle.value;

-//	if (cl.inwater)

-//		value *= 6;

-

-	if (side < cl_rollspeed.value)

-		side = side * value / cl_rollspeed.value;

-	else

-		side = value;

-	

-	return side*sign;

-	

-}

-

-

-/*

-===============

-V_CalcBob

-

-===============

-*/

-float V_CalcBob (void)

-{

-	float	bob;

-	float	cycle;

-	

-	cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value;

-	cycle /= cl_bobcycle.value;

-	if (cycle < cl_bobup.value)

-		cycle = M_PI * cycle / cl_bobup.value;

-	else

-		cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);

-

-// bob is proportional to velocity in the xy plane

-// (don't count Z, or jumping messes it up)

-

-	bob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value;

-//Con_Printf ("speed: %5.1f\n", Length(cl.velocity));

-	bob = bob*0.3 + bob*0.7*sin(cycle);

-	if (bob > 4)

-		bob = 4;

-	else if (bob < -7)

-		bob = -7;

-	return bob;

-	

-}

-

-

-//=============================================================================

-

-

-cvar_t	v_centermove = {"v_centermove", "0.15", false};

-cvar_t	v_centerspeed = {"v_centerspeed","500"};

-

-

-void V_StartPitchDrift (void)

-{

-#if 1

-	if (cl.laststop == cl.time)

-	{

-		return;		// something else is keeping it from drifting

-	}

-#endif

-	if (cl.nodrift || !cl.pitchvel)

-	{

-		cl.pitchvel = v_centerspeed.value;

-		cl.nodrift = false;

-		cl.driftmove = 0;

-	}

-}

-

-void V_StopPitchDrift (void)

-{

-	cl.laststop = cl.time;

-	cl.nodrift = true;

-	cl.pitchvel = 0;

-}

-

-/*

-===============

-V_DriftPitch

-

-Moves the client pitch angle towards cl.idealpitch sent by the server.

-

-If the user is adjusting pitch manually, either with lookup/lookdown,

-mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.

-

-Drifting is enabled when the center view key is hit, mlook is released and

-lookspring is non 0, or when 

-===============

-*/

-void V_DriftPitch (void)

-{

-	float		delta, move;

-

-	if (noclip_anglehack || !cl.onground || cls.demoplayback )

-	{

-		cl.driftmove = 0;

-		cl.pitchvel = 0;

-		return;

-	}

-

-// don't count small mouse motion

-	if (cl.nodrift)

-	{

-		if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value)

-			cl.driftmove = 0;

-		else

-			cl.driftmove += host_frametime;

-	

-		if ( cl.driftmove > v_centermove.value)

-		{

-			V_StartPitchDrift ();

-		}

-		return;

-	}

-	

-	delta = cl.idealpitch - cl.viewangles[PITCH];

-

-	if (!delta)

-	{

-		cl.pitchvel = 0;

-		return;

-	}

-

-	move = host_frametime * cl.pitchvel;

-	cl.pitchvel += host_frametime * v_centerspeed.value;

-	

-//Con_Printf ("move: %f (%f)\n", move, host_frametime);

-

-	if (delta > 0)

-	{

-		if (move > delta)

-		{

-			cl.pitchvel = 0;

-			move = delta;

-		}

-		cl.viewangles[PITCH] += move;

-	}

-	else if (delta < 0)

-	{

-		if (move > -delta)

-		{

-			cl.pitchvel = 0;

-			move = -delta;

-		}

-		cl.viewangles[PITCH] -= move;

-	}

-}

-

-

-

-

-

-/*

-============================================================================== 

- 

-						PALETTE FLASHES 

- 

-============================================================================== 

-*/ 

- 

- 

-cshift_t	cshift_empty = { {130,80,50}, 0 };

-cshift_t	cshift_water = { {130,80,50}, 128 };

-cshift_t	cshift_slime = { {0,25,5}, 150 };

-cshift_t	cshift_lava = { {255,80,0}, 150 };

-

-cvar_t		v_gamma = {"gamma", "1", true};

-

-byte		gammatable[256];	// palette is sent through this

-

-#ifdef	GLQUAKE

-byte		ramps[3][256];

-float		v_blend[4];		// rgba 0.0 - 1.0

-#endif	// GLQUAKE

-

-void BuildGammaTable (float g)

-{

-	int		i, inf;

-	

-	if (g == 1.0)

-	{

-		for (i=0 ; i<256 ; i++)

-			gammatable[i] = i;

-		return;

-	}

-	

-	for (i=0 ; i<256 ; i++)

-	{

-		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;

-		if (inf < 0)

-			inf = 0;

-		if (inf > 255)

-			inf = 255;

-		gammatable[i] = inf;

-	}

-}

-

-/*

-=================

-V_CheckGamma

-=================

-*/

-qboolean V_CheckGamma (void)

-{

-	static float oldgammavalue;

-	

-	if (v_gamma.value == oldgammavalue)

-		return false;

-	oldgammavalue = v_gamma.value;

-	

-	BuildGammaTable (v_gamma.value);

-	vid.recalc_refdef = 1;				// force a surface cache flush

-	

-	return true;

-}

-

-

-

-/*

-===============

-V_ParseDamage

-===============

-*/

-void V_ParseDamage (void)

-{

-	int		armor, blood;

-	vec3_t	from;

-	int		i;

-	vec3_t	forward, right, up;

-	entity_t	*ent;

-	float	side;

-	float	count;

-	

-	armor = MSG_ReadByte ();

-	blood = MSG_ReadByte ();

-	for (i=0 ; i<3 ; i++)

-		from[i] = MSG_ReadCoord ();

-

-	count = blood*0.5 + armor*0.5;

-	if (count < 10)

-		count = 10;

-

-	cl.faceanimtime = cl.time + 0.2;		// but sbar face into pain frame

-

-	cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;

-	if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)

-		cl.cshifts[CSHIFT_DAMAGE].percent = 0;

-	if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)

-		cl.cshifts[CSHIFT_DAMAGE].percent = 150;

-

-	if (armor > blood)		

-	{

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;

-	}

-	else if (armor)

-	{

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;

-	}

-	else

-	{

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;

-		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;

-	}

-

-//

-// calculate view angle kicks

-//

-	ent = &cl_entities[cl.viewentity];

-	

-	VectorSubtract (from, ent->origin, from);

-	VectorNormalize (from);

-	

-	AngleVectors (ent->angles, forward, right, up);

-

-	side = DotProduct (from, right);

-	v_dmg_roll = count*side*v_kickroll.value;

-	

-	side = DotProduct (from, forward);

-	v_dmg_pitch = count*side*v_kickpitch.value;

-

-	v_dmg_time = v_kicktime.value;

-}

-

-

-/*

-==================

-V_cshift_f

-==================

-*/

-void V_cshift_f (void)

-{

-	cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));

-	cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));

-	cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));

-	cshift_empty.percent = atoi(Cmd_Argv(4));

-}

-

-

-/*

-==================

-V_BonusFlash_f

-

-When you run over an item, the server sends this command

-==================

-*/

-void V_BonusFlash_f (void)

-{

-	cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;

-	cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;

-	cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;

-	cl.cshifts[CSHIFT_BONUS].percent = 50;

-}

-

-/*

-=============

-V_SetContentsColor

-

-Underwater, lava, etc each has a color shift

-=============

-*/

-void V_SetContentsColor (int contents)

-{

-	switch (contents)

-	{

-	case CONTENTS_EMPTY:

-	case CONTENTS_SOLID:

-		cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;

-		break;

-	case CONTENTS_LAVA:

-		cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;

-		break;

-	case CONTENTS_SLIME:

-		cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;

-		break;

-	default:

-		cl.cshifts[CSHIFT_CONTENTS] = cshift_water;

-	}

-}

-

-/*

-=============

-V_CalcPowerupCshift

-=============

-*/

-void V_CalcPowerupCshift (void)

-{

-	if (cl.items & IT_QUAD)

-	{

-		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;

-		cl.cshifts[CSHIFT_POWERUP].percent = 30;

-	}

-	else if (cl.items & IT_SUIT)

-	{

-		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;

-		cl.cshifts[CSHIFT_POWERUP].percent = 20;

-	}

-	else if (cl.items & IT_INVISIBILITY)

-	{

-		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;

-		cl.cshifts[CSHIFT_POWERUP].percent = 100;

-	}

-	else if (cl.items & IT_INVULNERABILITY)

-	{

-		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;

-		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;

-		cl.cshifts[CSHIFT_POWERUP].percent = 30;

-	}

-	else

-		cl.cshifts[CSHIFT_POWERUP].percent = 0;

-}

-

-/*

-=============

-V_CalcBlend

-=============

-*/

-#ifdef	GLQUAKE

-void V_CalcBlend (void)

-{

-	float	r, g, b, a, a2;

-	int		j;

-

-	r = 0;

-	g = 0;

-	b = 0;

-	a = 0;

-

-	for (j=0 ; j<NUM_CSHIFTS ; j++)	

-	{

-		if (!gl_cshiftpercent.value)

-			continue;

-

-		a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;

-

-//		a2 = cl.cshifts[j].percent/255.0;

-		if (!a2)

-			continue;

-		a = a + a2*(1-a);

-//Con_Printf ("j:%i a:%f\n", j, a);

-		a2 = a2/a;

-		r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;

-		g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;

-		b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;

-	}

-

-	v_blend[0] = r/255.0;

-	v_blend[1] = g/255.0;

-	v_blend[2] = b/255.0;

-	v_blend[3] = a;

-	if (v_blend[3] > 1)

-		v_blend[3] = 1;

-	if (v_blend[3] < 0)

-		v_blend[3] = 0;

-}

-#endif

-

-/*

-=============

-V_UpdatePalette

-=============

-*/

-#ifdef	GLQUAKE

-void V_UpdatePalette (void)

-{

-	int		i, j;

-	qboolean	new;

-	byte	*basepal, *newpal;

-	byte	pal[768];

-	float	r,g,b,a;

-	int		ir, ig, ib;

-	qboolean force;

-

-	V_CalcPowerupCshift ();

-	

-	new = false;

-	

-	for (i=0 ; i<NUM_CSHIFTS ; i++)

-	{

-		if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)

-		{

-			new = true;

-			cl.prev_cshifts[i].percent = cl.cshifts[i].percent;

-		}

-		for (j=0 ; j<3 ; j++)

-			if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])

-			{

-				new = true;

-				cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];

-			}

-	}

-	

-// drop the damage value

-	cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;

-	if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)

-		cl.cshifts[CSHIFT_DAMAGE].percent = 0;

-

-// drop the bonus value

-	cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;

-	if (cl.cshifts[CSHIFT_BONUS].percent <= 0)

-		cl.cshifts[CSHIFT_BONUS].percent = 0;

-

-	force = V_CheckGamma ();

-	if (!new && !force)

-		return;

-

-	V_CalcBlend ();

-

-	a = v_blend[3];

-	r = 255*v_blend[0]*a;

-	g = 255*v_blend[1]*a;

-	b = 255*v_blend[2]*a;

-

-	a = 1-a;

-	for (i=0 ; i<256 ; i++)

-	{

-		ir = i*a + r;

-		ig = i*a + g;

-		ib = i*a + b;

-		if (ir > 255)

-			ir = 255;

-		if (ig > 255)

-			ig = 255;

-		if (ib > 255)

-			ib = 255;

-

-		ramps[0][i] = gammatable[ir];

-		ramps[1][i] = gammatable[ig];

-		ramps[2][i] = gammatable[ib];

-	}

-

-	basepal = host_basepal;

-	newpal = pal;

-	

-	for (i=0 ; i<256 ; i++)

-	{

-		ir = basepal[0];

-		ig = basepal[1];

-		ib = basepal[2];

-		basepal += 3;

-		

-		newpal[0] = ramps[0][ir];

-		newpal[1] = ramps[1][ig];

-		newpal[2] = ramps[2][ib];

-		newpal += 3;

-	}

-

-	VID_ShiftPalette (pal);	

-}

-#else	// !GLQUAKE

-void V_UpdatePalette (void)

-{

-	int		i, j;

-	qboolean	new;

-	byte	*basepal, *newpal;

-	byte	pal[768];

-	int		r,g,b;

-	qboolean force;

-

-	V_CalcPowerupCshift ();

-	

-	new = false;

-	

-	for (i=0 ; i<NUM_CSHIFTS ; i++)

-	{

-		if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)

-		{

-			new = true;

-			cl.prev_cshifts[i].percent = cl.cshifts[i].percent;

-		}

-		for (j=0 ; j<3 ; j++)

-			if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])

-			{

-				new = true;

-				cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];

-			}

-	}

-	

-// drop the damage value

-	cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;

-	if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)

-		cl.cshifts[CSHIFT_DAMAGE].percent = 0;

-

-// drop the bonus value

-	cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;

-	if (cl.cshifts[CSHIFT_BONUS].percent <= 0)

-		cl.cshifts[CSHIFT_BONUS].percent = 0;

-

-	force = V_CheckGamma ();

-	if (!new && !force)

-		return;

-			

-	basepal = host_basepal;

-	newpal = pal;

-	

-	for (i=0 ; i<256 ; i++)

-	{

-		r = basepal[0];

-		g = basepal[1];

-		b = basepal[2];

-		basepal += 3;

-	

-		for (j=0 ; j<NUM_CSHIFTS ; j++)	

-		{

-			r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;

-			g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;

-			b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;

-		}

-		

-		newpal[0] = gammatable[r];

-		newpal[1] = gammatable[g];

-		newpal[2] = gammatable[b];

-		newpal += 3;

-	}

-

-	VID_ShiftPalette (pal);	

-}

-#endif	// !GLQUAKE

-

-

-/* 

-============================================================================== 

- 

-						VIEW RENDERING 

- 

-============================================================================== 

-*/ 

-

-float angledelta (float a)

-{

-	a = anglemod(a);

-	if (a > 180)

-		a -= 360;

-	return a;

-}

-

-/*

-==================

-CalcGunAngle

-==================

-*/

-void CalcGunAngle (void)

-{	

-	float	yaw, pitch, move;

-	static float oldyaw = 0;

-	static float oldpitch = 0;

-	

-	yaw = r_refdef.viewangles[YAW];

-	pitch = -r_refdef.viewangles[PITCH];

-

-	yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;

-	if (yaw > 10)

-		yaw = 10;

-	if (yaw < -10)

-		yaw = -10;

-	pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;

-	if (pitch > 10)

-		pitch = 10;

-	if (pitch < -10)

-		pitch = -10;

-	move = host_frametime*20;

-	if (yaw > oldyaw)

-	{

-		if (oldyaw + move < yaw)

-			yaw = oldyaw + move;

-	}

-	else

-	{

-		if (oldyaw - move > yaw)

-			yaw = oldyaw - move;

-	}

-	

-	if (pitch > oldpitch)

-	{

-		if (oldpitch + move < pitch)

-			pitch = oldpitch + move;

-	}

-	else

-	{

-		if (oldpitch - move > pitch)

-			pitch = oldpitch - move;

-	}

-	

-	oldyaw = yaw;

-	oldpitch = pitch;

-

-	cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;

-	cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);

-

-	cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;

-	cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;

-	cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;

-}

-

-/*

-==============

-V_BoundOffsets

-==============

-*/

-void V_BoundOffsets (void)

-{

-	entity_t	*ent;

-	

-	ent = &cl_entities[cl.viewentity];

-

-// absolutely bound refresh reletive to entity clipping hull

-// so the view can never be inside a solid wall

-

-	if (r_refdef.vieworg[0] < ent->origin[0] - 14)

-		r_refdef.vieworg[0] = ent->origin[0] - 14;

-	else if (r_refdef.vieworg[0] > ent->origin[0] + 14)

-		r_refdef.vieworg[0] = ent->origin[0] + 14;

-	if (r_refdef.vieworg[1] < ent->origin[1] - 14)

-		r_refdef.vieworg[1] = ent->origin[1] - 14;

-	else if (r_refdef.vieworg[1] > ent->origin[1] + 14)

-		r_refdef.vieworg[1] = ent->origin[1] + 14;

-	if (r_refdef.vieworg[2] < ent->origin[2] - 22)

-		r_refdef.vieworg[2] = ent->origin[2] - 22;

-	else if (r_refdef.vieworg[2] > ent->origin[2] + 30)

-		r_refdef.vieworg[2] = ent->origin[2] + 30;

-}

-

-/*

-==============

-V_AddIdle

-

-Idle swaying

-==============

-*/

-void V_AddIdle (void)

-{

-	r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;

-	r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;

-	r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;

-}

-

-

-/*

-==============

-V_CalcViewRoll

-

-Roll is induced by movement and damage

-==============

-*/

-void V_CalcViewRoll (void)

-{

-	float		side;

-		

-	side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);

-	r_refdef.viewangles[ROLL] += side;

-

-	if (v_dmg_time > 0)

-	{

-		r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;

-		r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;

-		v_dmg_time -= host_frametime;

-	}

-

-	if (cl.stats[STAT_HEALTH] <= 0)

-	{

-		r_refdef.viewangles[ROLL] = 80;	// dead view angle

-		return;

-	}

-

-}

-

-

-/*

-==================

-V_CalcIntermissionRefdef

-

-==================

-*/

-void V_CalcIntermissionRefdef (void)

-{

-	entity_t	*ent, *view;

-	float		old;

-

-// ent is the player model (visible when out of body)

-	ent = &cl_entities[cl.viewentity];

-// view is the weapon model (only visible from inside body)

-	view = &cl.viewent;

-

-	VectorCopy (ent->origin, r_refdef.vieworg);

-	VectorCopy (ent->angles, r_refdef.viewangles);

-	view->model = NULL;

-

-// allways idle in intermission

-	old = v_idlescale.value;

-	v_idlescale.value = 1;

-	V_AddIdle ();

-	v_idlescale.value = old;

-}

-

-/*

-==================

-V_CalcRefdef

-

-==================

-*/

-void V_CalcRefdef (void)

-{

-	entity_t	*ent, *view;

-	int			i;

-	vec3_t		forward, right, up;

-	vec3_t		angles;

-	float		bob;

-	static float oldz = 0;

-

-	V_DriftPitch ();

-

-// ent is the player model (visible when out of body)

-	ent = &cl_entities[cl.viewentity];

-// view is the weapon model (only visible from inside body)

-	view = &cl.viewent;

-	

-

-// transform the view offset by the model's matrix to get the offset from

-// model origin for the view

-	ent->angles[YAW] = cl.viewangles[YAW];	// the model should face

-										// the view dir

-	ent->angles[PITCH] = -cl.viewangles[PITCH];	// the model should face

-										// the view dir

-										

-	

-	bob = V_CalcBob ();

-	

-// refresh position

-	VectorCopy (ent->origin, r_refdef.vieworg);

-	r_refdef.vieworg[2] += cl.viewheight + bob;

-

-// never let it sit exactly on a node line, because a water plane can

-// dissapear when viewed with the eye exactly on it.

-// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis

-	r_refdef.vieworg[0] += 1.0/32;

-	r_refdef.vieworg[1] += 1.0/32;

-	r_refdef.vieworg[2] += 1.0/32;

-

-	VectorCopy (cl.viewangles, r_refdef.viewangles);

-	V_CalcViewRoll ();

-	V_AddIdle ();

-

-// offsets

-	angles[PITCH] = -ent->angles[PITCH];	// because entity pitches are

-											//  actually backward

-	angles[YAW] = ent->angles[YAW];

-	angles[ROLL] = ent->angles[ROLL];

-

-	AngleVectors (angles, forward, right, up);

-

-	for (i=0 ; i<3 ; i++)

-		r_refdef.vieworg[i] += scr_ofsx.value*forward[i]

-			+ scr_ofsy.value*right[i]

-			+ scr_ofsz.value*up[i];

-	

-	

-	V_BoundOffsets ();

-		

-// set up gun position

-	VectorCopy (cl.viewangles, view->angles);

-	

-	CalcGunAngle ();

-

-	VectorCopy (ent->origin, view->origin);

-	view->origin[2] += cl.viewheight;

-

-	for (i=0 ; i<3 ; i++)

-	{

-		view->origin[i] += forward[i]*bob*0.4;

-//		view->origin[i] += right[i]*bob*0.4;

-//		view->origin[i] += up[i]*bob*0.8;

-	}

-	view->origin[2] += bob;

-

-// fudge position around to keep amount of weapon visible

-// roughly equal with different FOV

-

-#if 0

-	if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name,  "progs/v_shot2.mdl"))

-#endif

-	if (scr_viewsize.value == 110)

-		view->origin[2] += 1;

-	else if (scr_viewsize.value == 100)

-		view->origin[2] += 2;

-	else if (scr_viewsize.value == 90)

-		view->origin[2] += 1;

-	else if (scr_viewsize.value == 80)

-		view->origin[2] += 0.5;

-

-	view->model = cl.model_precache[cl.stats[STAT_WEAPON]];

-	view->frame = cl.stats[STAT_WEAPONFRAME];

-	view->colormap = vid.colormap;

-

-// set up the refresh position

-	VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);

-

-// smooth out stair step ups

-if (cl.onground && ent->origin[2] - oldz > 0)

-{

-	float steptime;

-	

-	steptime = cl.time - cl.oldtime;

-	if (steptime < 0)

-//FIXME		I_Error ("steptime < 0");

-		steptime = 0;

-

-	oldz += steptime * 80;

-	if (oldz > ent->origin[2])

-		oldz = ent->origin[2];

-	if (ent->origin[2] - oldz > 12)

-		oldz = ent->origin[2] - 12;

-	r_refdef.vieworg[2] += oldz - ent->origin[2];

-	view->origin[2] += oldz - ent->origin[2];

-}

-else

-	oldz = ent->origin[2];

-

-	if (chase_active.value)

-		Chase_Update ();

-}

-

-/*

-==================

-V_RenderView

-

-The player's clipping box goes from (-16 -16 -24) to (16 16 32) from

-the entity origin, so any view position inside that will be valid

-==================

-*/

-extern vrect_t	scr_vrect;

-

-void V_RenderView (void)

-{

-	if (con_forcedup)

-		return;

-

-// don't allow cheats in multiplayer

-	if (cl.maxclients > 1)

-	{

-		Cvar_Set ("scr_ofsx", "0");

-		Cvar_Set ("scr_ofsy", "0");

-		Cvar_Set ("scr_ofsz", "0");

-	}

-

-	if (cl.intermission)

-	{	// intermission / finale rendering

-		V_CalcIntermissionRefdef ();	

-	}

-	else

-	{

-		if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ )

-			V_CalcRefdef ();

-	}

-

-	R_PushDlights ();

-

-	if (lcd_x.value)

-	{

-		//

-		// render two interleaved views

-		//

-		int		i;

-

-		vid.rowbytes <<= 1;

-		vid.aspect *= 0.5;

-

-		r_refdef.viewangles[YAW] -= lcd_yaw.value;

-		for (i=0 ; i<3 ; i++)

-			r_refdef.vieworg[i] -= right[i]*lcd_x.value;

-		R_RenderView ();

-

-		vid.buffer += vid.rowbytes>>1;

-

-		R_PushDlights ();

-

-		r_refdef.viewangles[YAW] += lcd_yaw.value*2;

-		for (i=0 ; i<3 ; i++)

-			r_refdef.vieworg[i] += 2*right[i]*lcd_x.value;

-		R_RenderView ();

-

-		vid.buffer -= vid.rowbytes>>1;

-

-		r_refdef.vrect.height <<= 1;

-

-		vid.rowbytes >>= 1;

-		vid.aspect *= 2;

-	}

-	else

-	{

-		R_RenderView ();

-	}

-

-#ifndef GLQUAKE

-	if (crosshair.value)

-		Draw_Character (scr_vrect.x + scr_vrect.width/2 + cl_crossx.value, 

-			scr_vrect.y + scr_vrect.height/2 + cl_crossy.value, '+');

-#endif

-		

-}

-

-//============================================================================

-

-/*

-=============

-V_Init

-=============

-*/

-void V_Init (void)

-{

-	Cmd_AddCommand ("v_cshift", V_cshift_f);	

-	Cmd_AddCommand ("bf", V_BonusFlash_f);

-	Cmd_AddCommand ("centerview", V_StartPitchDrift);

-

-	Cvar_RegisterVariable (&lcd_x);

-	Cvar_RegisterVariable (&lcd_yaw);

-

-	Cvar_RegisterVariable (&v_centermove);

-	Cvar_RegisterVariable (&v_centerspeed);

-

-	Cvar_RegisterVariable (&v_iyaw_cycle);

-	Cvar_RegisterVariable (&v_iroll_cycle);

-	Cvar_RegisterVariable (&v_ipitch_cycle);

-	Cvar_RegisterVariable (&v_iyaw_level);

-	Cvar_RegisterVariable (&v_iroll_level);

-	Cvar_RegisterVariable (&v_ipitch_level);

-

-	Cvar_RegisterVariable (&v_idlescale);

-	Cvar_RegisterVariable (&crosshair);

-	Cvar_RegisterVariable (&cl_crossx);

-	Cvar_RegisterVariable (&cl_crossy);

-	Cvar_RegisterVariable (&gl_cshiftpercent);

-

-	Cvar_RegisterVariable (&scr_ofsx);

-	Cvar_RegisterVariable (&scr_ofsy);

-	Cvar_RegisterVariable (&scr_ofsz);

-	Cvar_RegisterVariable (&cl_rollspeed);

-	Cvar_RegisterVariable (&cl_rollangle);

-	Cvar_RegisterVariable (&cl_bob);

-	Cvar_RegisterVariable (&cl_bobcycle);

-	Cvar_RegisterVariable (&cl_bobup);

-

-	Cvar_RegisterVariable (&v_kicktime);

-	Cvar_RegisterVariable (&v_kickroll);

-	Cvar_RegisterVariable (&v_kickpitch);	

-	

-	BuildGammaTable (1.0);	// no gamma yet

-	Cvar_RegisterVariable (&v_gamma);

-}

-

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// view.c -- player eye positioning
+
+#include "quakedef.h"
+#include "r_local.h"
+
+/*
+
+The view is allowed to move slightly from it's true position for bobbing,
+but if it exceeds 8 pixels linear distance (spherical, not box), the list of
+entities sent from the server may not include everything in the pvs, especially
+when crossing a water boudnary.
+
+*/
+
+cvar_t		lcd_x = CVAR2("lcd_x","0");
+cvar_t		lcd_yaw = CVAR2("lcd_yaw","0");
+
+cvar_t	scr_ofsx = CVAR3("scr_ofsx","0", false);
+cvar_t	scr_ofsy = CVAR3("scr_ofsy","0", false);
+cvar_t	scr_ofsz = CVAR3("scr_ofsz","0", false);
+
+cvar_t	cl_rollspeed = CVAR2("cl_rollspeed", "200");
+cvar_t	cl_rollangle =  CVAR2("cl_rollangle", "2.0");
+
+cvar_t	cl_bob = CVAR3("cl_bob","0.02", false);
+cvar_t	cl_bobcycle = CVAR3("cl_bobcycle","0.6", false);
+cvar_t	cl_bobup = CVAR3("cl_bobup","0.5", false);
+
+cvar_t	v_kicktime = CVAR3("v_kicktime", "0.5", false);
+cvar_t	v_kickroll = CVAR3("v_kickroll", "0.6", false);
+cvar_t	v_kickpitch = CVAR3("v_kickpitch", "0.6", false);
+
+cvar_t	v_iyaw_cycle = CVAR3("v_iyaw_cycle", "2", false);
+cvar_t	v_iroll_cycle = CVAR3("v_iroll_cycle", "0.5", false);
+cvar_t	v_ipitch_cycle = CVAR3("v_ipitch_cycle", "1", false);
+cvar_t	v_iyaw_level = CVAR3("v_iyaw_level", "0.3", false);
+cvar_t	v_iroll_level = CVAR3("v_iroll_level", "0.1", false);
+cvar_t	v_ipitch_level = CVAR3("v_ipitch_level", "0.3", false);
+
+cvar_t	v_idlescale = CVAR3("v_idlescale", "0", false);
+
+cvar_t	crosshair = CVAR3("crosshair", "0", true);
+cvar_t	cl_crossx = CVAR3("cl_crossx", "0", false);
+cvar_t	cl_crossy = CVAR3("cl_crossy", "0", false);
+
+cvar_t	gl_cshiftpercent = CVAR3("gl_cshiftpercent", "100", false);
+
+float	v_dmg_time, v_dmg_roll, v_dmg_pitch;
+
+extern	int			in_forward, in_forward2, in_back;
+
+
+/*
+===============
+V_CalcRoll
+
+Used by view and sv_user
+===============
+*/
+vec3_t	forward, right, up;
+
+float V_CalcRoll (vec3_t angles, vec3_t velocity)
+{
+	float	sign;
+	float	side;
+	float	value;
+	
+	AngleVectors (angles, forward, right, up);
+	side = DotProduct (velocity, right);
+	sign = side < 0 ? -1 : 1;
+	side = fabs(side);
+	
+	value = cl_rollangle.value;
+//	if (cl.inwater)
+//		value *= 6;
+
+	if (side < cl_rollspeed.value)
+		side = side * value / cl_rollspeed.value;
+	else
+		side = value;
+	
+	return side*sign;
+	
+}
+
+
+/*
+===============
+V_CalcBob
+
+===============
+*/
+float V_CalcBob (void)
+{
+	float	bob;
+	float	cycle;
+	
+	cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value;
+	cycle /= cl_bobcycle.value;
+	if (cycle < cl_bobup.value)
+		cycle = M_PI * cycle / cl_bobup.value;
+	else
+		cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);
+
+// bob is proportional to velocity in the xy plane
+// (don't count Z, or jumping messes it up)
+
+	bob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value;
+//Con_Printf ("speed: %5.1f\n", Length(cl.velocity));
+	bob = bob*0.3 + bob*0.7*sin(cycle);
+	if (bob > 4)
+		bob = 4;
+	else if (bob < -7)
+		bob = -7;
+	return bob;
+	
+}
+
+
+//=============================================================================
+
+
+cvar_t	v_centermove = CVAR3("v_centermove", "0.15", false);
+cvar_t	v_centerspeed = CVAR2("v_centerspeed","500");
+
+
+void V_StartPitchDrift (void)
+{
+#if 1
+	if (cl.laststop == cl.time)
+	{
+		return;		// something else is keeping it from drifting
+	}
+#endif
+	if (cl.nodrift || !cl.pitchvel)
+	{
+		cl.pitchvel = v_centerspeed.value;
+		cl.nodrift = false;
+		cl.driftmove = 0;
+	}
+}
+
+void V_StopPitchDrift (void)
+{
+	cl.laststop = cl.time;
+	cl.nodrift = true;
+	cl.pitchvel = 0;
+}
+
+/*
+===============
+V_DriftPitch
+
+Moves the client pitch angle towards cl.idealpitch sent by the server.
+
+If the user is adjusting pitch manually, either with lookup/lookdown,
+mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
+
+Drifting is enabled when the center view key is hit, mlook is released and
+lookspring is non 0, or when 
+===============
+*/
+void V_DriftPitch (void)
+{
+	float		delta, move;
+
+	if (noclip_anglehack || !cl.onground || cls.demoplayback )
+	{
+		cl.driftmove = 0;
+		cl.pitchvel = 0;
+		return;
+	}
+
+// don't count small mouse motion
+	if (cl.nodrift)
+	{
+		if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value)
+			cl.driftmove = 0;
+		else
+			cl.driftmove += host_frametime;
+	
+		if ( cl.driftmove > v_centermove.value)
+		{
+			V_StartPitchDrift ();
+		}
+		return;
+	}
+	
+	delta = cl.idealpitch - cl.viewangles[PITCH];
+
+	if (!delta)
+	{
+		cl.pitchvel = 0;
+		return;
+	}
+
+	move = host_frametime * cl.pitchvel;
+	cl.pitchvel += host_frametime * v_centerspeed.value;
+	
+//Con_Printf ("move: %f (%f)\n", move, host_frametime);
+
+	if (delta > 0)
+	{
+		if (move > delta)
+		{
+			cl.pitchvel = 0;
+			move = delta;
+		}
+		cl.viewangles[PITCH] += move;
+	}
+	else if (delta < 0)
+	{
+		if (move > -delta)
+		{
+			cl.pitchvel = 0;
+			move = -delta;
+		}
+		cl.viewangles[PITCH] -= move;
+	}
+}
+
+
+
+
+
+/*
+============================================================================== 
+ 
+						PALETTE FLASHES 
+ 
+============================================================================== 
+*/ 
+ 
+ 
+cshift_t	cshift_empty = { {130,80,50}, 0 };
+cshift_t	cshift_water = { {130,80,50}, 128 };
+cshift_t	cshift_slime = { {0,25,5}, 150 };
+cshift_t	cshift_lava = { {255,80,0}, 150 };
+
+cvar_t		v_gamma = CVAR3("gamma", "1", true);
+
+byte		gammatable[256];	// palette is sent through this
+
+#ifdef	GLQUAKE
+byte		ramps[3][256];
+float		v_blend[4];		// rgba 0.0 - 1.0
+#endif	// GLQUAKE
+
+void BuildGammaTable (float g)
+{
+	int		i, inf;
+	
+	if (g == 1.0)
+	{
+		for (i=0 ; i<256 ; i++)
+			gammatable[i] = i;
+		return;
+	}
+	
+	for (i=0 ; i<256 ; i++)
+	{
+		inf = (int) (255 * pow ( (i+0.5)/255.5 , g ) + 0.5);
+		if (inf < 0)
+			inf = 0;
+		if (inf > 255)
+			inf = 255;
+		gammatable[i] = inf;
+	}
+}
+
+/*
+=================
+V_CheckGamma
+=================
+*/
+qboolean V_CheckGamma (void)
+{
+	static float oldgammavalue;
+	
+	if (v_gamma.value == oldgammavalue)
+		return false;
+	oldgammavalue = v_gamma.value;
+	
+	BuildGammaTable (v_gamma.value);
+	vid.recalc_refdef = 1;				// force a surface cache flush
+	
+	return true;
+}
+
+
+
+/*
+===============
+V_ParseDamage
+===============
+*/
+void V_ParseDamage (void)
+{
+	int		armor, blood;
+	vec3_t	from;
+	int		i;
+	vec3_t	forward, right, up;
+	entity_t	*ent;
+	float	side;
+	float	count;
+	
+	armor = MSG_ReadByte ();
+	blood = MSG_ReadByte ();
+	for (i=0 ; i<3 ; i++)
+		from[i] = MSG_ReadCoord ();
+
+	count = blood*0.5 + armor*0.5;
+	if (count < 10)
+		count = 10;
+
+	cl.faceanimtime = cl.time + 0.2;		// but sbar face into pain frame
+
+	cl.cshifts[CSHIFT_DAMAGE].percent += (int) (3*count);
+	if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
+		cl.cshifts[CSHIFT_DAMAGE].percent = 0;
+	if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
+		cl.cshifts[CSHIFT_DAMAGE].percent = 150;
+
+	if (armor > blood)		
+	{
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
+	}
+	else if (armor)
+	{
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
+	}
+	else
+	{
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
+		cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
+	}
+
+//
+// calculate view angle kicks
+//
+	ent = &cl_entities[cl.viewentity];
+	
+	VectorSubtract (from, ent->origin, from);
+	VectorNormalize (from);
+	
+	AngleVectors (ent->angles, forward, right, up);
+
+	side = DotProduct (from, right);
+	v_dmg_roll = count*side*v_kickroll.value;
+	
+	side = DotProduct (from, forward);
+	v_dmg_pitch = count*side*v_kickpitch.value;
+
+	v_dmg_time = v_kicktime.value;
+}
+
+
+/*
+==================
+V_cshift_f
+==================
+*/
+void V_cshift_f (void)
+{
+	cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));
+	cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));
+	cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));
+	cshift_empty.percent = atoi(Cmd_Argv(4));
+}
+
+
+/*
+==================
+V_BonusFlash_f
+
+When you run over an item, the server sends this command
+==================
+*/
+void V_BonusFlash_f (void)
+{
+	cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
+	cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
+	cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
+	cl.cshifts[CSHIFT_BONUS].percent = 50;
+}
+
+/*
+=============
+V_SetContentsColor
+
+Underwater, lava, etc each has a color shift
+=============
+*/
+void V_SetContentsColor (int contents)
+{
+	switch (contents)
+	{
+	case CONTENTS_EMPTY:
+	case CONTENTS_SOLID:
+		cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
+		break;
+	case CONTENTS_LAVA:
+		cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
+		break;
+	case CONTENTS_SLIME:
+		cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
+		break;
+	default:
+		cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
+	}
+}
+
+/*
+=============
+V_CalcPowerupCshift
+=============
+*/
+void V_CalcPowerupCshift (void)
+{
+	if (cl.items & IT_QUAD)
+	{
+		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
+		cl.cshifts[CSHIFT_POWERUP].percent = 30;
+	}
+	else if (cl.items & IT_SUIT)
+	{
+		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
+		cl.cshifts[CSHIFT_POWERUP].percent = 20;
+	}
+	else if (cl.items & IT_INVISIBILITY)
+	{
+		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
+		cl.cshifts[CSHIFT_POWERUP].percent = 100;
+	}
+	else if (cl.items & IT_INVULNERABILITY)
+	{
+		cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
+		cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
+		cl.cshifts[CSHIFT_POWERUP].percent = 30;
+	}
+	else
+		cl.cshifts[CSHIFT_POWERUP].percent = 0;
+}
+
+/*
+=============
+V_CalcBlend
+=============
+*/
+#ifdef	GLQUAKE
+void V_CalcBlend (void)
+{
+	float	r, g, b, a, a2;
+	int		j;
+
+	r = 0;
+	g = 0;
+	b = 0;
+	a = 0;
+
+	for (j=0 ; j<NUM_CSHIFTS ; j++)	
+	{
+		if (!gl_cshiftpercent.value)
+			continue;
+
+		a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
+
+//		a2 = cl.cshifts[j].percent/255.0;
+		if (!a2)
+			continue;
+		a = a + a2*(1-a);
+//Con_Printf ("j:%i a:%f\n", j, a);
+		a2 = a2/a;
+		r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;
+		g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;
+		b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;
+	}
+
+	v_blend[0] = r/255.0;
+	v_blend[1] = g/255.0;
+	v_blend[2] = b/255.0;
+	v_blend[3] = a;
+	if (v_blend[3] > 1)
+		v_blend[3] = 1;
+	if (v_blend[3] < 0)
+		v_blend[3] = 0;
+}
+#endif
+
+/*
+=============
+V_UpdatePalette
+=============
+*/
+#ifdef	GLQUAKE
+void V_UpdatePalette (void)
+{
+	int		i, j;
+	qboolean	newb;
+	byte	*basepal, *newpal;
+	byte	pal[768];
+	float	r,g,b,a;
+	int		ir, ig, ib;
+	qboolean force;
+
+	V_CalcPowerupCshift ();
+	
+	newb = false;
+	
+	for (i=0 ; i<NUM_CSHIFTS ; i++)
+	{
+		if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
+		{
+			newb = true;
+			cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
+		}
+		for (j=0 ; j<3 ; j++)
+			if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
+			{
+				newb = true;
+				cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
+			}
+	}
+	
+// drop the damage value
+	cl.cshifts[CSHIFT_DAMAGE].percent -= (int)(host_frametime*150);
+	if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
+		cl.cshifts[CSHIFT_DAMAGE].percent = 0;
+
+// drop the bonus value
+	cl.cshifts[CSHIFT_BONUS].percent -= (int)(host_frametime*100);
+	if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
+		cl.cshifts[CSHIFT_BONUS].percent = 0;
+
+	force = V_CheckGamma ();
+	if (!newb && !force)
+		return;
+
+	V_CalcBlend ();
+
+	a = v_blend[3];
+	r = 255*v_blend[0]*a;
+	g = 255*v_blend[1]*a;
+	b = 255*v_blend[2]*a;
+
+	a = 1-a;
+	for (i=0 ; i<256 ; i++)
+	{
+		ir = (int) (i*a + r);
+		ig = (int) (i*a + g);
+		ib = (int) (i*a + b);
+		if (ir > 255)
+			ir = 255;
+		if (ig > 255)
+			ig = 255;
+		if (ib > 255)
+			ib = 255;
+
+		ramps[0][i] = gammatable[ir];
+		ramps[1][i] = gammatable[ig];
+		ramps[2][i] = gammatable[ib];
+	}
+
+	basepal = host_basepal;
+	newpal = pal;
+	
+	for (i=0 ; i<256 ; i++)
+	{
+		ir = basepal[0];
+		ig = basepal[1];
+		ib = basepal[2];
+		basepal += 3;
+		
+		newpal[0] = ramps[0][ir];
+		newpal[1] = ramps[1][ig];
+		newpal[2] = ramps[2][ib];
+		newpal += 3;
+	}
+
+	VID_ShiftPalette (pal);	
+}
+#else	// !GLQUAKE
+void V_UpdatePalette (void)
+{
+	int		i, j;
+	qboolean	new;
+	byte	*basepal, *newpal;
+	byte	pal[768];
+	int		r,g,b;
+	qboolean force;
+
+	V_CalcPowerupCshift ();
+	
+	new = false;
+	
+	for (i=0 ; i<NUM_CSHIFTS ; i++)
+	{
+		if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
+		{
+			new = true;
+			cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
+		}
+		for (j=0 ; j<3 ; j++)
+			if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
+			{
+				new = true;
+				cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
+			}
+	}
+	
+// drop the damage value
+	cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
+	if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
+		cl.cshifts[CSHIFT_DAMAGE].percent = 0;
+
+// drop the bonus value
+	cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
+	if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
+		cl.cshifts[CSHIFT_BONUS].percent = 0;
+
+	force = V_CheckGamma ();
+	if (!new && !force)
+		return;
+			
+	basepal = host_basepal;
+	newpal = pal;
+	
+	for (i=0 ; i<256 ; i++)
+	{
+		r = basepal[0];
+		g = basepal[1];
+		b = basepal[2];
+		basepal += 3;
+	
+		for (j=0 ; j<NUM_CSHIFTS ; j++)	
+		{
+			r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;
+			g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;
+			b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;
+		}
+		
+		newpal[0] = gammatable[r];
+		newpal[1] = gammatable[g];
+		newpal[2] = gammatable[b];
+		newpal += 3;
+	}
+
+	VID_ShiftPalette (pal);	
+}
+#endif	// !GLQUAKE
+
+
+/* 
+============================================================================== 
+ 
+						VIEW RENDERING 
+ 
+============================================================================== 
+*/ 
+
+float angledelta (float a)
+{
+	a = anglemod(a);
+	if (a > 180)
+		a -= 360;
+	return a;
+}
+
+/*
+==================
+CalcGunAngle
+==================
+*/
+void CalcGunAngle (void)
+{	
+	float	yaw, pitch, move;
+	static float oldyaw = 0;
+	static float oldpitch = 0;
+	
+	yaw = r_refdef.viewangles[YAW];
+	pitch = -r_refdef.viewangles[PITCH];
+
+	yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
+	if (yaw > 10)
+		yaw = 10;
+	if (yaw < -10)
+		yaw = -10;
+	pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
+	if (pitch > 10)
+		pitch = 10;
+	if (pitch < -10)
+		pitch = -10;
+	move = host_frametime*20;
+	if (yaw > oldyaw)
+	{
+		if (oldyaw + move < yaw)
+			yaw = oldyaw + move;
+	}
+	else
+	{
+		if (oldyaw - move > yaw)
+			yaw = oldyaw - move;
+	}
+	
+	if (pitch > oldpitch)
+	{
+		if (oldpitch + move < pitch)
+			pitch = oldpitch + move;
+	}
+	else
+	{
+		if (oldpitch - move > pitch)
+			pitch = oldpitch - move;
+	}
+	
+	oldyaw = yaw;
+	oldpitch = pitch;
+
+	cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
+	cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
+
+	cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
+	cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
+	cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
+}
+
+/*
+==============
+V_BoundOffsets
+==============
+*/
+void V_BoundOffsets (void)
+{
+	entity_t	*ent;
+	
+	ent = &cl_entities[cl.viewentity];
+
+// absolutely bound refresh reletive to entity clipping hull
+// so the view can never be inside a solid wall
+
+	if (r_refdef.vieworg[0] < ent->origin[0] - 14)
+		r_refdef.vieworg[0] = ent->origin[0] - 14;
+	else if (r_refdef.vieworg[0] > ent->origin[0] + 14)
+		r_refdef.vieworg[0] = ent->origin[0] + 14;
+	if (r_refdef.vieworg[1] < ent->origin[1] - 14)
+		r_refdef.vieworg[1] = ent->origin[1] - 14;
+	else if (r_refdef.vieworg[1] > ent->origin[1] + 14)
+		r_refdef.vieworg[1] = ent->origin[1] + 14;
+	if (r_refdef.vieworg[2] < ent->origin[2] - 22)
+		r_refdef.vieworg[2] = ent->origin[2] - 22;
+	else if (r_refdef.vieworg[2] > ent->origin[2] + 30)
+		r_refdef.vieworg[2] = ent->origin[2] + 30;
+}
+
+/*
+==============
+V_AddIdle
+
+Idle swaying
+==============
+*/
+void V_AddIdle (void)
+{
+	r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
+	r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
+	r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
+}
+
+
+/*
+==============
+V_CalcViewRoll
+
+Roll is induced by movement and damage
+==============
+*/
+void V_CalcViewRoll (void)
+{
+	float		side;
+		
+	side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);
+	r_refdef.viewangles[ROLL] += side;
+
+	if (v_dmg_time > 0)
+	{
+		r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
+		r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
+		v_dmg_time -= host_frametime;
+	}
+
+	if (cl.stats[STAT_HEALTH] <= 0)
+	{
+		r_refdef.viewangles[ROLL] = 80;	// dead view angle
+		return;
+	}
+
+}
+
+
+/*
+==================
+V_CalcIntermissionRefdef
+
+==================
+*/
+void V_CalcIntermissionRefdef (void)
+{
+	entity_t	*ent, *view;
+	float		old;
+
+// ent is the player model (visible when out of body)
+	ent = &cl_entities[cl.viewentity];
+// view is the weapon model (only visible from inside body)
+	view = &cl.viewent;
+
+	VectorCopy (ent->origin, r_refdef.vieworg);
+	VectorCopy (ent->angles, r_refdef.viewangles);
+	view->model = NULL;
+
+// allways idle in intermission
+	old = v_idlescale.value;
+	v_idlescale.value = 1;
+	V_AddIdle ();
+	v_idlescale.value = old;
+}
+
+/*
+==================
+V_CalcRefdef
+
+==================
+*/
+void V_CalcRefdef (void)
+{
+	entity_t	*ent, *view;
+	int			i;
+	vec3_t		forward, right, up;
+	vec3_t		angles;
+	float		bob;
+	static float oldz = 0;
+
+	V_DriftPitch ();
+
+// ent is the player model (visible when out of body)
+	ent = &cl_entities[cl.viewentity];
+// view is the weapon model (only visible from inside body)
+	view = &cl.viewent;
+	
+
+// transform the view offset by the model's matrix to get the offset from
+// model origin for the view
+	ent->angles[YAW] = cl.viewangles[YAW];	// the model should face
+										// the view dir
+	ent->angles[PITCH] = -cl.viewangles[PITCH];	// the model should face
+										// the view dir
+										
+	
+	bob = V_CalcBob ();
+	
+// refresh position
+	VectorCopy (ent->origin, r_refdef.vieworg);
+	r_refdef.vieworg[2] += cl.viewheight + bob;
+
+// never let it sit exactly on a node line, because a water plane can
+// dissapear when viewed with the eye exactly on it.
+// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis
+	r_refdef.vieworg[0] += 1.0/32;
+	r_refdef.vieworg[1] += 1.0/32;
+	r_refdef.vieworg[2] += 1.0/32;
+
+	VectorCopy (cl.viewangles, r_refdef.viewangles);
+	V_CalcViewRoll ();
+	V_AddIdle ();
+
+// offsets
+	angles[PITCH] = -ent->angles[PITCH];	// because entity pitches are
+											//  actually backward
+	angles[YAW] = ent->angles[YAW];
+	angles[ROLL] = ent->angles[ROLL];
+
+	AngleVectors (angles, forward, right, up);
+
+	for (i=0 ; i<3 ; i++)
+		r_refdef.vieworg[i] += scr_ofsx.value*forward[i]
+			+ scr_ofsy.value*right[i]
+			+ scr_ofsz.value*up[i];
+	
+	
+	V_BoundOffsets ();
+		
+// set up gun position
+	VectorCopy (cl.viewangles, view->angles);
+	
+	CalcGunAngle ();
+
+	VectorCopy (ent->origin, view->origin);
+	view->origin[2] += cl.viewheight;
+
+	for (i=0 ; i<3 ; i++)
+	{
+		view->origin[i] += forward[i]*bob*0.4;
+//		view->origin[i] += right[i]*bob*0.4;
+//		view->origin[i] += up[i]*bob*0.8;
+	}
+	view->origin[2] += bob;
+
+// fudge position around to keep amount of weapon visible
+// roughly equal with different FOV
+
+#if 0
+	if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name,  "progs/v_shot2.mdl"))
+#endif
+	if (scr_viewsize.value == 110)
+		view->origin[2] += 1;
+	else if (scr_viewsize.value == 100)
+		view->origin[2] += 2;
+	else if (scr_viewsize.value == 90)
+		view->origin[2] += 1;
+	else if (scr_viewsize.value == 80)
+		view->origin[2] += 0.5;
+
+	view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
+	view->frame = cl.stats[STAT_WEAPONFRAME];
+	view->colormap = vid.colormap;
+
+// set up the refresh position
+	VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);
+
+// smooth out stair step ups
+if (cl.onground && ent->origin[2] - oldz > 0)
+{
+	float steptime;
+	
+	steptime = cl.time - cl.oldtime;
+	if (steptime < 0)
+//FIXME		I_Error ("steptime < 0");
+		steptime = 0;
+
+	oldz += steptime * 80;
+	if (oldz > ent->origin[2])
+		oldz = ent->origin[2];
+	if (ent->origin[2] - oldz > 12)
+		oldz = ent->origin[2] - 12;
+	r_refdef.vieworg[2] += oldz - ent->origin[2];
+	view->origin[2] += oldz - ent->origin[2];
+}
+else
+	oldz = ent->origin[2];
+
+	if (chase_active.value)
+		Chase_Update ();
+}
+
+/*
+==================
+V_RenderView
+
+The player's clipping box goes from (-16 -16 -24) to (16 16 32) from
+the entity origin, so any view position inside that will be valid
+==================
+*/
+extern vrect_t	scr_vrect;
+
+void V_RenderView (void)
+{
+	if (con_forcedup)
+		return;
+
+// don't allow cheats in multiplayer
+	if (cl.maxclients > 1)
+	{
+		Cvar_Set ("scr_ofsx", "0");
+		Cvar_Set ("scr_ofsy", "0");
+		Cvar_Set ("scr_ofsz", "0");
+	}
+
+	if (cl.intermission)
+	{	// intermission / finale rendering
+		V_CalcIntermissionRefdef ();	
+	}
+	else
+	{
+		if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ )
+			V_CalcRefdef ();
+	}
+
+	R_PushDlights ();
+
+	if (lcd_x.value)
+	{
+		//
+		// render two interleaved views
+		//
+		int		i;
+
+		vid.rowbytes <<= 1;
+		vid.aspect *= 0.5;
+
+		r_refdef.viewangles[YAW] -= lcd_yaw.value;
+		for (i=0 ; i<3 ; i++)
+			r_refdef.vieworg[i] -= right[i]*lcd_x.value;
+		R_RenderView ();
+
+		vid.buffer += vid.rowbytes>>1;
+
+		R_PushDlights ();
+
+		r_refdef.viewangles[YAW] += lcd_yaw.value*2;
+		for (i=0 ; i<3 ; i++)
+			r_refdef.vieworg[i] += 2*right[i]*lcd_x.value;
+		R_RenderView ();
+
+		vid.buffer -= vid.rowbytes>>1;
+
+		r_refdef.vrect.height <<= 1;
+
+		vid.rowbytes >>= 1;
+		vid.aspect *= 2;
+	}
+	else
+	{
+		R_RenderView ();
+	}
+
+#ifndef GLQUAKE
+	if (crosshair.value)
+		Draw_Character (scr_vrect.x + scr_vrect.width/2 + cl_crossx.value, 
+			scr_vrect.y + scr_vrect.height/2 + cl_crossy.value, '+');
+#endif
+		
+}
+
+//============================================================================
+
+/*
+=============
+V_Init
+=============
+*/
+void V_Init (void)
+{
+	Cmd_AddCommand ("v_cshift", V_cshift_f);	
+	Cmd_AddCommand ("bf", V_BonusFlash_f);
+	Cmd_AddCommand ("centerview", V_StartPitchDrift);
+
+	Cvar_RegisterVariable (&lcd_x);
+	Cvar_RegisterVariable (&lcd_yaw);
+
+	Cvar_RegisterVariable (&v_centermove);
+	Cvar_RegisterVariable (&v_centerspeed);
+
+	Cvar_RegisterVariable (&v_iyaw_cycle);
+	Cvar_RegisterVariable (&v_iroll_cycle);
+	Cvar_RegisterVariable (&v_ipitch_cycle);
+	Cvar_RegisterVariable (&v_iyaw_level);
+	Cvar_RegisterVariable (&v_iroll_level);
+	Cvar_RegisterVariable (&v_ipitch_level);
+
+	Cvar_RegisterVariable (&v_idlescale);
+	Cvar_RegisterVariable (&crosshair);
+	Cvar_RegisterVariable (&cl_crossx);
+	Cvar_RegisterVariable (&cl_crossy);
+	Cvar_RegisterVariable (&gl_cshiftpercent);
+
+	Cvar_RegisterVariable (&scr_ofsx);
+	Cvar_RegisterVariable (&scr_ofsy);
+	Cvar_RegisterVariable (&scr_ofsz);
+	Cvar_RegisterVariable (&cl_rollspeed);
+	Cvar_RegisterVariable (&cl_rollangle);
+	Cvar_RegisterVariable (&cl_bob);
+	Cvar_RegisterVariable (&cl_bobcycle);
+	Cvar_RegisterVariable (&cl_bobup);
+
+	Cvar_RegisterVariable (&v_kicktime);
+	Cvar_RegisterVariable (&v_kickroll);
+	Cvar_RegisterVariable (&v_kickpitch);	
+	
+	BuildGammaTable (1.0);	// no gamma yet
+	Cvar_RegisterVariable (&v_gamma);
+}
+
+
diff --git a/quake/src/WinQuake/vregset.c b/quake/src/WinQuake/vregset.cpp
old mode 100644
new mode 100755
similarity index 100%
rename from quake/src/WinQuake/vregset.c
rename to quake/src/WinQuake/vregset.cpp
diff --git a/quake/src/WinQuake/wad.c b/quake/src/WinQuake/wad.cpp
old mode 100644
new mode 100755
similarity index 92%
rename from quake/src/WinQuake/wad.c
rename to quake/src/WinQuake/wad.cpp
index 1eb8b59..f7dde93
--- a/quake/src/WinQuake/wad.c
+++ b/quake/src/WinQuake/wad.cpp
@@ -1,158 +1,158 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// wad.c

-

-#include "quakedef.h"

-

-int			wad_numlumps;

-lumpinfo_t	*wad_lumps;

-byte		*wad_base;

-

-void SwapPic (qpic_t *pic);

-

-/*

-==================

-W_CleanupName

-

-Lowercases name and pads with spaces and a terminating 0 to the length of

-lumpinfo_t->name.

-Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time

-Space padding is so names can be printed nicely in tables.

-Can safely be performed in place.

-==================

-*/

-void W_CleanupName (char *in, char *out)

-{

-	int		i;

-	int		c;

-	

-	for (i=0 ; i<16 ; i++ )

-	{

-		c = in[i];

-		if (!c)

-			break;

-			

-		if (c >= 'A' && c <= 'Z')

-			c += ('a' - 'A');

-		out[i] = c;

-	}

-	

-	for ( ; i< 16 ; i++ )

-		out[i] = 0;

-}

-

-

-

-/*

-====================

-W_LoadWadFile

-====================

-*/

-void W_LoadWadFile (char *filename)

-{

-	lumpinfo_t		*lump_p;

-	wadinfo_t		*header;

-	unsigned		i;

-	int				infotableofs;

-	

-	wad_base = COM_LoadHunkFile (filename);

-	if (!wad_base)

-		Sys_Error ("W_LoadWadFile: couldn't load %s", filename);

-

-	header = (wadinfo_t *)wad_base;

-	

-	if (header->identification[0] != 'W'

-	|| header->identification[1] != 'A'

-	|| header->identification[2] != 'D'

-	|| header->identification[3] != '2')

-		Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename);

-		

-	wad_numlumps = LittleLong(header->numlumps);

-	infotableofs = LittleLong(header->infotableofs);

-	wad_lumps = (lumpinfo_t *)(wad_base + infotableofs);

-	

-	for (i=0, lump_p = wad_lumps ; i<wad_numlumps ; i++,lump_p++)

-	{

-		lump_p->filepos = LittleLong(lump_p->filepos);

-		lump_p->size = LittleLong(lump_p->size);

-		W_CleanupName (lump_p->name, lump_p->name);

-		if (lump_p->type == TYP_QPIC)

-			SwapPic ( (qpic_t *)(wad_base + lump_p->filepos));

-	}

-}

-

-

-/*

-=============

-W_GetLumpinfo

-=============

-*/

-lumpinfo_t	*W_GetLumpinfo (char *name)

-{

-	int		i;

-	lumpinfo_t	*lump_p;

-	char	clean[16];

-	

-	W_CleanupName (name, clean);

-	

-	for (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++)

-	{

-		if (!strcmp(clean, lump_p->name))

-			return lump_p;

-	}

-	

-	Sys_Error ("W_GetLumpinfo: %s not found", name);

-	return NULL;

-}

-

-void *W_GetLumpName (char *name)

-{

-	lumpinfo_t	*lump;

-	

-	lump = W_GetLumpinfo (name);

-	

-	return (void *)(wad_base + lump->filepos);

-}

-

-void *W_GetLumpNum (int num)

-{

-	lumpinfo_t	*lump;

-	

-	if (num < 0 || num > wad_numlumps)

-		Sys_Error ("W_GetLumpNum: bad number: %i", num);

-		

-	lump = wad_lumps + num;

-	

-	return (void *)(wad_base + lump->filepos);

-}

-

-/*

-=============================================================================

-

-automatic byte swapping

-

-=============================================================================

-*/

-

-void SwapPic (qpic_t *pic)

-{

-	pic->width = LittleLong(pic->width);

-	pic->height = LittleLong(pic->height);	

-}

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// wad.c
+
+#include "quakedef.h"
+
+int			wad_numlumps;
+lumpinfo_t	*wad_lumps;
+byte		*wad_base;
+
+void SwapPic (qpic_t *pic);
+
+/*
+==================
+W_CleanupName
+
+Lowercases name and pads with spaces and a terminating 0 to the length of
+lumpinfo_t->name.
+Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time
+Space padding is so names can be printed nicely in tables.
+Can safely be performed in place.
+==================
+*/
+void W_CleanupName (const char *in, char *out)
+{
+	int		i;
+	int		c;
+	
+	for (i=0 ; i<16 ; i++ )
+	{
+		c = in[i];
+		if (!c)
+			break;
+			
+		if (c >= 'A' && c <= 'Z')
+			c += ('a' - 'A');
+		out[i] = c;
+	}
+	
+	for ( ; i< 16 ; i++ )
+		out[i] = 0;
+}
+
+
+
+/*
+====================
+W_LoadWadFile
+====================
+*/
+void W_LoadWadFile (const char *filename)
+{
+	lumpinfo_t		*lump_p;
+	wadinfo_t		*header;
+	unsigned		i;
+	int				infotableofs;
+	
+	wad_base = COM_LoadHunkFile (filename);
+	if (!wad_base)
+		Sys_Error ("W_LoadWadFile: couldn't load %s", filename);
+
+	header = (wadinfo_t *)wad_base;
+	
+	if (header->identification[0] != 'W'
+	|| header->identification[1] != 'A'
+	|| header->identification[2] != 'D'
+	|| header->identification[3] != '2')
+		Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename);
+		
+	wad_numlumps = LittleLong(header->numlumps);
+	infotableofs = LittleLong(header->infotableofs);
+	wad_lumps = (lumpinfo_t *)(wad_base + infotableofs);
+	
+	for (i=0, lump_p = wad_lumps ; i< (unsigned) wad_numlumps ; i++,lump_p++)
+	{
+		lump_p->filepos = LittleLong(lump_p->filepos);
+		lump_p->size = LittleLong(lump_p->size);
+		W_CleanupName (lump_p->name, lump_p->name);
+		if (lump_p->type == TYP_QPIC)
+			SwapPic ( (qpic_t *)(wad_base + lump_p->filepos));
+	}
+}
+
+
+/*
+=============
+W_GetLumpinfo
+=============
+*/
+lumpinfo_t	*W_GetLumpinfo (const char *name)
+{
+	int		i;
+	lumpinfo_t	*lump_p;
+	char	clean[16];
+	
+	W_CleanupName (name, clean);
+	
+	for (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++)
+	{
+		if (!strcmp(clean, lump_p->name))
+			return lump_p;
+	}
+	
+	Sys_Error ("W_GetLumpinfo: %s not found", name);
+	return NULL;
+}
+
+void *W_GetLumpName (const char *name)
+{
+	lumpinfo_t	*lump;
+	
+	lump = W_GetLumpinfo (name);
+	
+	return (void *)(wad_base + lump->filepos);
+}
+
+void *W_GetLumpNum (int num)
+{
+	lumpinfo_t	*lump;
+	
+	if (num < 0 || num > wad_numlumps)
+		Sys_Error ("W_GetLumpNum: bad number: %i", num);
+		
+	lump = wad_lumps + num;
+	
+	return (void *)(wad_base + lump->filepos);
+}
+
+/*
+=============================================================================
+
+automatic byte swapping
+
+=============================================================================
+*/
+
+void SwapPic (qpic_t *pic)
+{
+	pic->width = LittleLong(pic->width);
+	pic->height = LittleLong(pic->height);	
+}
diff --git a/quake/src/WinQuake/wad.h b/quake/src/WinQuake/wad.h
index 125f5d7..3d6b472 100644
--- a/quake/src/WinQuake/wad.h
+++ b/quake/src/WinQuake/wad.h
@@ -1,75 +1,75 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// wad.h

-

-//===============

-//   TYPES

-//===============

-

-#define	CMP_NONE		0

-#define	CMP_LZSS		1

-

-#define	TYP_NONE		0

-#define	TYP_LABEL		1

-

-#define	TYP_LUMPY		64				// 64 + grab command number

-#define	TYP_PALETTE		64

-#define	TYP_QTEX		65

-#define	TYP_QPIC		66

-#define	TYP_SOUND		67

-#define	TYP_MIPTEX		68

-

-typedef struct

-{

-	int			width, height;

-	byte		data[4];			// variably sized

-} qpic_t;

-

-

-

-typedef struct

-{

-	char		identification[4];		// should be WAD2 or 2DAW

-	int			numlumps;

-	int			infotableofs;

-} wadinfo_t;

-

-typedef struct

-{

-	int			filepos;

-	int			disksize;

-	int			size;					// uncompressed

-	char		type;

-	char		compression;

-	char		pad1, pad2;

-	char		name[16];				// must be null terminated

-} lumpinfo_t;

-

-extern	int			wad_numlumps;

-extern	lumpinfo_t	*wad_lumps;

-extern	byte		*wad_base;

-

-void	W_LoadWadFile (char *filename);

-void	W_CleanupName (char *in, char *out);

-lumpinfo_t	*W_GetLumpinfo (char *name);

-void	*W_GetLumpName (char *name);

-void	*W_GetLumpNum (int num);

-

-void SwapPic (qpic_t *pic);

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// wad.h
+
+//===============
+//   TYPES
+//===============
+
+#define	CMP_NONE		0
+#define	CMP_LZSS		1
+
+#define	TYP_NONE		0
+#define	TYP_LABEL		1
+
+#define	TYP_LUMPY		64				// 64 + grab command number
+#define	TYP_PALETTE		64
+#define	TYP_QTEX		65
+#define	TYP_QPIC		66
+#define	TYP_SOUND		67
+#define	TYP_MIPTEX		68
+
+typedef struct
+{
+	int			width, height;
+	byte		data[4];			// variably sized
+} qpic_t;
+
+
+
+typedef struct
+{
+	char		identification[4];		// should be WAD2 or 2DAW
+	int			numlumps;
+	int			infotableofs;
+} wadinfo_t;
+
+typedef struct
+{
+	int			filepos;
+	int			disksize;
+	int			size;					// uncompressed
+	char		type;
+	char		compression;
+	char		pad1, pad2;
+	char		name[16];				// must be null terminated
+} lumpinfo_t;
+
+extern	int			wad_numlumps;
+extern	lumpinfo_t	*wad_lumps;
+extern	byte		*wad_base;
+
+void	W_LoadWadFile (const char *filename);
+void	W_CleanupName (const char *in, char *out);
+lumpinfo_t	*W_GetLumpinfo (const char *name);
+void	*W_GetLumpName (const char *name);
+void	*W_GetLumpNum (int num);
+
+void SwapPic (qpic_t *pic);
diff --git a/quake/src/WinQuake/world.c b/quake/src/WinQuake/world.cpp
old mode 100644
new mode 100755
similarity index 86%
rename from quake/src/WinQuake/world.c
rename to quake/src/WinQuake/world.cpp
index ccb7cd8..e9e7934
--- a/quake/src/WinQuake/world.c
+++ b/quake/src/WinQuake/world.cpp
@@ -1,962 +1,962 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// world.c -- world query functions

-

-#include "quakedef.h"

-

-/*

-

-entities never clip against themselves, or their owner

-

-line of sight checks trace->crosscontent, but bullets don't

-

-*/

-

-

-typedef struct

-{

-	vec3_t		boxmins, boxmaxs;// enclose the test object along entire move

-	float		*mins, *maxs;	// size of the moving object

-	vec3_t		mins2, maxs2;	// size when clipping against mosnters

-	float		*start, *end;

-	trace_t		trace;

-	int			type;

-	edict_t		*passedict;

-} moveclip_t;

-

-

-int SV_HullPointContents (hull_t *hull, int num, vec3_t p);

-

-/*

-===============================================================================

-

-HULL BOXES

-

-===============================================================================

-*/

-

-

-static	hull_t		box_hull;

-static	dclipnode_t	box_clipnodes[6];

-static	mplane_t	box_planes[6];

-

-/*

-===================

-SV_InitBoxHull

-

-Set up the planes and clipnodes so that the six floats of a bounding box

-can just be stored out and get a proper hull_t structure.

-===================

-*/

-void SV_InitBoxHull (void)

-{

-	int		i;

-	int		side;

-

-	box_hull.clipnodes = box_clipnodes;

-	box_hull.planes = box_planes;

-	box_hull.firstclipnode = 0;

-	box_hull.lastclipnode = 5;

-

-	for (i=0 ; i<6 ; i++)

-	{

-		box_clipnodes[i].planenum = i;

-		

-		side = i&1;

-		

-		box_clipnodes[i].children[side] = CONTENTS_EMPTY;

-		if (i != 5)

-			box_clipnodes[i].children[side^1] = i + 1;

-		else

-			box_clipnodes[i].children[side^1] = CONTENTS_SOLID;

-		

-		box_planes[i].type = i>>1;

-		box_planes[i].normal[i>>1] = 1;

-	}

-	

-}

-

-

-/*

-===================

-SV_HullForBox

-

-To keep everything totally uniform, bounding boxes are turned into small

-BSP trees instead of being compared directly.

-===================

-*/

-hull_t	*SV_HullForBox (vec3_t mins, vec3_t maxs)

-{

-	box_planes[0].dist = maxs[0];

-	box_planes[1].dist = mins[0];

-	box_planes[2].dist = maxs[1];

-	box_planes[3].dist = mins[1];

-	box_planes[4].dist = maxs[2];

-	box_planes[5].dist = mins[2];

-

-	return &box_hull;

-}

-

-

-

-/*

-================

-SV_HullForEntity

-

-Returns a hull that can be used for testing or clipping an object of mins/maxs

-size.

-Offset is filled in to contain the adjustment that must be added to the

-testing object's origin to get a point to use with the returned hull.

-================

-*/

-hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)

-{

-	model_t		*model;

-	vec3_t		size;

-	vec3_t		hullmins, hullmaxs;

-	hull_t		*hull;

-

-// decide which clipping hull to use, based on the size

-	if (ent->v.solid == SOLID_BSP)

-	{	// explicit hulls in the BSP model

-		if (ent->v.movetype != MOVETYPE_PUSH)

-			Sys_Error ("SOLID_BSP without MOVETYPE_PUSH");

-

-		model = sv.models[ (int)ent->v.modelindex ];

-

-		if (!model || model->type != mod_brush)

-			Sys_Error ("MOVETYPE_PUSH with a non bsp model");

-

-		VectorSubtract (maxs, mins, size);

-		if (size[0] < 3)

-			hull = &model->hulls[0];

-		else if (size[0] <= 32)

-			hull = &model->hulls[1];

-		else

-			hull = &model->hulls[2];

-

-// calculate an offset value to center the origin

-		VectorSubtract (hull->clip_mins, mins, offset);

-		VectorAdd (offset, ent->v.origin, offset);

-	}

-	else

-	{	// create a temp hull from bounding box sizes

-

-		VectorSubtract (ent->v.mins, maxs, hullmins);

-		VectorSubtract (ent->v.maxs, mins, hullmaxs);

-		hull = SV_HullForBox (hullmins, hullmaxs);

-		

-		VectorCopy (ent->v.origin, offset);

-	}

-

-

-	return hull;

-}

-

-/*

-===============================================================================

-

-ENTITY AREA CHECKING

-

-===============================================================================

-*/

-

-typedef struct areanode_s

-{

-	int		axis;		// -1 = leaf node

-	float	dist;

-	struct areanode_s	*children[2];

-	link_t	trigger_edicts;

-	link_t	solid_edicts;

-} areanode_t;

-

-#define	AREA_DEPTH	4

-#define	AREA_NODES	32

-

-static	areanode_t	sv_areanodes[AREA_NODES];

-static	int			sv_numareanodes;

-

-/*

-===============

-SV_CreateAreaNode

-

-===============

-*/

-areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)

-{

-	areanode_t	*anode;

-	vec3_t		size;

-	vec3_t		mins1, maxs1, mins2, maxs2;

-

-	anode = &sv_areanodes[sv_numareanodes];

-	sv_numareanodes++;

-

-	ClearLink (&anode->trigger_edicts);

-	ClearLink (&anode->solid_edicts);

-	

-	if (depth == AREA_DEPTH)

-	{

-		anode->axis = -1;

-		anode->children[0] = anode->children[1] = NULL;

-		return anode;

-	}

-	

-	VectorSubtract (maxs, mins, size);

-	if (size[0] > size[1])

-		anode->axis = 0;

-	else

-		anode->axis = 1;

-	

-	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);

-	VectorCopy (mins, mins1);	

-	VectorCopy (mins, mins2);	

-	VectorCopy (maxs, maxs1);	

-	VectorCopy (maxs, maxs2);	

-	

-	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;

-	

-	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);

-	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);

-

-	return anode;

-}

-

-/*

-===============

-SV_ClearWorld

-

-===============

-*/

-void SV_ClearWorld (void)

-{

-	SV_InitBoxHull ();

-	

-	memset (sv_areanodes, 0, sizeof(sv_areanodes));

-	sv_numareanodes = 0;

-	SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);

-}

-

-

-/*

-===============

-SV_UnlinkEdict

-

-===============

-*/

-void SV_UnlinkEdict (edict_t *ent)

-{

-	if (!ent->area.prev)

-		return;		// not linked in anywhere

-	RemoveLink (&ent->area);

-	ent->area.prev = ent->area.next = NULL;

-}

-

-

-/*

-====================

-SV_TouchLinks

-====================

-*/

-void SV_TouchLinks ( edict_t *ent, areanode_t *node )

-{

-	link_t		*l, *next;

-	edict_t		*touch;

-	int			old_self, old_other;

-

-// touch linked edicts

-	for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)

-	{

-		next = l->next;

-		touch = EDICT_FROM_AREA(l);

-		if (touch == ent)

-			continue;

-		if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)

-			continue;

-		if (ent->v.absmin[0] > touch->v.absmax[0]

-		|| ent->v.absmin[1] > touch->v.absmax[1]

-		|| ent->v.absmin[2] > touch->v.absmax[2]

-		|| ent->v.absmax[0] < touch->v.absmin[0]

-		|| ent->v.absmax[1] < touch->v.absmin[1]

-		|| ent->v.absmax[2] < touch->v.absmin[2] )

-			continue;

-		old_self = pr_global_struct->self;

-		old_other = pr_global_struct->other;

-

-		pr_global_struct->self = EDICT_TO_PROG(touch);

-		pr_global_struct->other = EDICT_TO_PROG(ent);

-		pr_global_struct->time = sv.time;

-		PR_ExecuteProgram (touch->v.touch);

-

-		pr_global_struct->self = old_self;

-		pr_global_struct->other = old_other;

-	}

-	

-// recurse down both sides

-	if (node->axis == -1)

-		return;

-	

-	if ( ent->v.absmax[node->axis] > node->dist )

-		SV_TouchLinks ( ent, node->children[0] );

-	if ( ent->v.absmin[node->axis] < node->dist )

-		SV_TouchLinks ( ent, node->children[1] );

-}

-

-

-/*

-===============

-SV_FindTouchedLeafs

-

-===============

-*/

-void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)

-{

-	mplane_t	*splitplane;

-	mleaf_t		*leaf;

-	int			sides;

-	int			leafnum;

-

-	if (node->contents == CONTENTS_SOLID)

-		return;

-	

-// add an efrag if the node is a leaf

-

-	if ( node->contents < 0)

-	{

-		if (ent->num_leafs == MAX_ENT_LEAFS)

-			return;

-

-		leaf = (mleaf_t *)node;

-		leafnum = leaf - sv.worldmodel->leafs - 1;

-

-		ent->leafnums[ent->num_leafs] = leafnum;

-		ent->num_leafs++;			

-		return;

-	}

-	

-// NODE_MIXED

-

-	splitplane = node->plane;

-	sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane);

-	

-// recurse down the contacted sides

-	if (sides & 1)

-		SV_FindTouchedLeafs (ent, node->children[0]);

-		

-	if (sides & 2)

-		SV_FindTouchedLeafs (ent, node->children[1]);

-}

-

-/*

-===============

-SV_LinkEdict

-

-===============

-*/

-void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)

-{

-	areanode_t	*node;

-

-	if (ent->area.prev)

-		SV_UnlinkEdict (ent);	// unlink from old position

-		

-	if (ent == sv.edicts)

-		return;		// don't add the world

-

-	if (ent->free)

-		return;

-

-// set the abs box

-

-#ifdef QUAKE2

-	if (ent->v.solid == SOLID_BSP && 

-	(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )

-	{	// expand for rotation

-		float		max, v;

-		int			i;

-

-		max = 0;

-		for (i=0 ; i<3 ; i++)

-		{

-			v =fabs( ent->v.mins[i]);

-			if (v > max)

-				max = v;

-			v =fabs( ent->v.maxs[i]);

-			if (v > max)

-				max = v;

-		}

-		for (i=0 ; i<3 ; i++)

-		{

-			ent->v.absmin[i] = ent->v.origin[i] - max;

-			ent->v.absmax[i] = ent->v.origin[i] + max;

-		}

-	}

-	else

-#endif

-	{

-		VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);	

-		VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax);

-	}

-

-//

-// to make items easier to pick up and allow them to be grabbed off

-// of shelves, the abs sizes are expanded

-//

-	if ((int)ent->v.flags & FL_ITEM)

-	{

-		ent->v.absmin[0] -= 15;

-		ent->v.absmin[1] -= 15;

-		ent->v.absmax[0] += 15;

-		ent->v.absmax[1] += 15;

-	}

-	else

-	{	// because movement is clipped an epsilon away from an actual edge,

-		// we must fully check even when bounding boxes don't quite touch

-		ent->v.absmin[0] -= 1;

-		ent->v.absmin[1] -= 1;

-		ent->v.absmin[2] -= 1;

-		ent->v.absmax[0] += 1;

-		ent->v.absmax[1] += 1;

-		ent->v.absmax[2] += 1;

-	}

-	

-// link to PVS leafs

-	ent->num_leafs = 0;

-	if (ent->v.modelindex)

-		SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);

-

-	if (ent->v.solid == SOLID_NOT)

-		return;

-

-// find the first node that the ent's box crosses

-	node = sv_areanodes;

-	while (1)

-	{

-		if (node->axis == -1)

-			break;

-		if (ent->v.absmin[node->axis] > node->dist)

-			node = node->children[0];

-		else if (ent->v.absmax[node->axis] < node->dist)

-			node = node->children[1];

-		else

-			break;		// crosses the node

-	}

-	

-// link it in	

-

-	if (ent->v.solid == SOLID_TRIGGER)

-		InsertLinkBefore (&ent->area, &node->trigger_edicts);

-	else

-		InsertLinkBefore (&ent->area, &node->solid_edicts);

-	

-// if touch_triggers, touch all entities at this node and decend for more

-	if (touch_triggers)

-		SV_TouchLinks ( ent, sv_areanodes );

-}

-

-

-

-/*

-===============================================================================

-

-POINT TESTING IN HULLS

-

-===============================================================================

-*/

-

-#if	!id386

-

-/*

-==================

-SV_HullPointContents

-

-==================

-*/

-int SV_HullPointContents (hull_t *hull, int num, vec3_t p)

-{

-	float		d;

-	dclipnode_t	*node;

-	mplane_t	*plane;

-

-	while (num >= 0)

-	{

-		if (num < hull->firstclipnode || num > hull->lastclipnode)

-			Sys_Error ("SV_HullPointContents: bad node number");

-	

-		node = hull->clipnodes + num;

-		plane = hull->planes + node->planenum;

-		

-		if (plane->type < 3)

-			d = p[plane->type] - plane->dist;

-		else

-			d = DotProduct (plane->normal, p) - plane->dist;

-		if (d < 0)

-			num = node->children[1];

-		else

-			num = node->children[0];

-	}

-	

-	return num;

-}

-

-#endif	// !id386

-

-

-/*

-==================

-SV_PointContents

-

-==================

-*/

-int SV_PointContents (vec3_t p)

-{

-	int		cont;

-

-	cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);

-	if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)

-		cont = CONTENTS_WATER;

-	return cont;

-}

-

-int SV_TruePointContents (vec3_t p)

-{

-	return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);

-}

-

-//===========================================================================

-

-/*

-============

-SV_TestEntityPosition

-

-This could be a lot more efficient...

-============

-*/

-edict_t	*SV_TestEntityPosition (edict_t *ent)

-{

-	trace_t	trace;

-

-	trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent);

-	

-	if (trace.startsolid)

-		return sv.edicts;

-		

-	return NULL;

-}

-

-

-/*

-===============================================================================

-

-LINE TESTING IN HULLS

-

-===============================================================================

-*/

-

-// 1/32 epsilon to keep floating point happy

-#define	DIST_EPSILON	(0.03125)

-

-/*

-==================

-SV_RecursiveHullCheck

-

-==================

-*/

-qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)

-{

-	dclipnode_t	*node;

-	mplane_t	*plane;

-	float		t1, t2;

-	float		frac;

-	int			i;

-	vec3_t		mid;

-	int			side;

-	float		midf;

-

-// check for empty

-	if (num < 0)

-	{

-		if (num != CONTENTS_SOLID)

-		{

-			trace->allsolid = false;

-			if (num == CONTENTS_EMPTY)

-				trace->inopen = true;

-			else

-				trace->inwater = true;

-		}

-		else

-			trace->startsolid = true;

-		return true;		// empty

-	}

-

-	if (num < hull->firstclipnode || num > hull->lastclipnode)

-		Sys_Error ("SV_RecursiveHullCheck: bad node number");

-

-//

-// find the point distances

-//

-	node = hull->clipnodes + num;

-	plane = hull->planes + node->planenum;

-

-	if (plane->type < 3)

-	{

-		t1 = p1[plane->type] - plane->dist;

-		t2 = p2[plane->type] - plane->dist;

-	}

-	else

-	{

-		t1 = DotProduct (plane->normal, p1) - plane->dist;

-		t2 = DotProduct (plane->normal, p2) - plane->dist;

-	}

-	

-#if 1

-	if (t1 >= 0 && t2 >= 0)

-		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);

-	if (t1 < 0 && t2 < 0)

-		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);

-#else

-	if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )

-		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);

-	if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )

-		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);

-#endif

-

-// put the crosspoint DIST_EPSILON pixels on the near side

-	if (t1 < 0)

-		frac = (t1 + DIST_EPSILON)/(t1-t2);

-	else

-		frac = (t1 - DIST_EPSILON)/(t1-t2);

-	if (frac < 0)

-		frac = 0;

-	if (frac > 1)

-		frac = 1;

-		

-	midf = p1f + (p2f - p1f)*frac;

-	for (i=0 ; i<3 ; i++)

-		mid[i] = p1[i] + frac*(p2[i] - p1[i]);

-

-	side = (t1 < 0);

-

-// move up to the node

-	if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )

-		return false;

-

-#ifdef PARANOID

-	if (SV_HullPointContents (sv_hullmodel, mid, node->children[side])

-	== CONTENTS_SOLID)

-	{

-		Con_Printf ("mid PointInHullSolid\n");

-		return false;

-	}

-#endif

-	

-	if (SV_HullPointContents (hull, node->children[side^1], mid)

-	!= CONTENTS_SOLID)

-// go past the node

-		return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);

-	

-	if (trace->allsolid)

-		return false;		// never got out of the solid area

-		

-//==================

-// the other side of the node is solid, this is the impact point

-//==================

-	if (!side)

-	{

-		VectorCopy (plane->normal, trace->plane.normal);

-		trace->plane.dist = plane->dist;

-	}

-	else

-	{

-		VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);

-		trace->plane.dist = -plane->dist;

-	}

-

-	while (SV_HullPointContents (hull, hull->firstclipnode, mid)

-	== CONTENTS_SOLID)

-	{ // shouldn't really happen, but does occasionally

-		frac -= 0.1;

-		if (frac < 0)

-		{

-			trace->fraction = midf;

-			VectorCopy (mid, trace->endpos);

-			Con_DPrintf ("backup past 0\n");

-			return false;

-		}

-		midf = p1f + (p2f - p1f)*frac;

-		for (i=0 ; i<3 ; i++)

-			mid[i] = p1[i] + frac*(p2[i] - p1[i]);

-	}

-

-	trace->fraction = midf;

-	VectorCopy (mid, trace->endpos);

-

-	return false;

-}

-

-

-/*

-==================

-SV_ClipMoveToEntity

-

-Handles selection or creation of a clipping hull, and offseting (and

-eventually rotation) of the end points

-==================

-*/

-trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)

-{

-	trace_t		trace;

-	vec3_t		offset;

-	vec3_t		start_l, end_l;

-	hull_t		*hull;

-

-// fill in a default trace

-	memset (&trace, 0, sizeof(trace_t));

-	trace.fraction = 1;

-	trace.allsolid = true;

-	VectorCopy (end, trace.endpos);

-

-// get the clipping hull

-	hull = SV_HullForEntity (ent, mins, maxs, offset);

-

-	VectorSubtract (start, offset, start_l);

-	VectorSubtract (end, offset, end_l);

-

-#ifdef QUAKE2

-	// rotate start and end into the models frame of reference

-	if (ent->v.solid == SOLID_BSP && 

-	(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )

-	{

-		vec3_t	a;

-		vec3_t	forward, right, up;

-		vec3_t	temp;

-

-		AngleVectors (ent->v.angles, forward, right, up);

-

-		VectorCopy (start_l, temp);

-		start_l[0] = DotProduct (temp, forward);

-		start_l[1] = -DotProduct (temp, right);

-		start_l[2] = DotProduct (temp, up);

-

-		VectorCopy (end_l, temp);

-		end_l[0] = DotProduct (temp, forward);

-		end_l[1] = -DotProduct (temp, right);

-		end_l[2] = DotProduct (temp, up);

-	}

-#endif

-

-// trace a line through the apropriate clipping hull

-	SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);

-

-#ifdef QUAKE2

-	// rotate endpos back to world frame of reference

-	if (ent->v.solid == SOLID_BSP && 

-	(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )

-	{

-		vec3_t	a;

-		vec3_t	forward, right, up;

-		vec3_t	temp;

-

-		if (trace.fraction != 1)

-		{

-			VectorSubtract (vec3_origin, ent->v.angles, a);

-			AngleVectors (a, forward, right, up);

-

-			VectorCopy (trace.endpos, temp);

-			trace.endpos[0] = DotProduct (temp, forward);

-			trace.endpos[1] = -DotProduct (temp, right);

-			trace.endpos[2] = DotProduct (temp, up);

-

-			VectorCopy (trace.plane.normal, temp);

-			trace.plane.normal[0] = DotProduct (temp, forward);

-			trace.plane.normal[1] = -DotProduct (temp, right);

-			trace.plane.normal[2] = DotProduct (temp, up);

-		}

-	}

-#endif

-

-// fix trace up by the offset

-	if (trace.fraction != 1)

-		VectorAdd (trace.endpos, offset, trace.endpos);

-

-// did we clip the move?

-	if (trace.fraction < 1 || trace.startsolid  )

-		trace.ent = ent;

-

-	return trace;

-}

-

-//===========================================================================

-

-/*

-====================

-SV_ClipToLinks

-

-Mins and maxs enclose the entire area swept by the move

-====================

-*/

-void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )

-{

-	link_t		*l, *next;

-	edict_t		*touch;

-	trace_t		trace;

-

-// touch linked edicts

-	for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)

-	{

-		next = l->next;

-		touch = EDICT_FROM_AREA(l);

-		if (touch->v.solid == SOLID_NOT)

-			continue;

-		if (touch == clip->passedict)

-			continue;

-		if (touch->v.solid == SOLID_TRIGGER)

-			Sys_Error ("Trigger in clipping list");

-

-		if (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP)

-			continue;

-

-		if (clip->boxmins[0] > touch->v.absmax[0]

-		|| clip->boxmins[1] > touch->v.absmax[1]

-		|| clip->boxmins[2] > touch->v.absmax[2]

-		|| clip->boxmaxs[0] < touch->v.absmin[0]

-		|| clip->boxmaxs[1] < touch->v.absmin[1]

-		|| clip->boxmaxs[2] < touch->v.absmin[2] )

-			continue;

-

-		if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])

-			continue;	// points never interact

-

-	// might intersect, so do an exact clip

-		if (clip->trace.allsolid)

-			return;

-		if (clip->passedict)

-		{

-		 	if (PROG_TO_EDICT(touch->v.owner) == clip->passedict)

-				continue;	// don't clip against own missiles

-			if (PROG_TO_EDICT(clip->passedict->v.owner) == touch)

-				continue;	// don't clip against owner

-		}

-

-		if ((int)touch->v.flags & FL_MONSTER)

-			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);

-		else

-			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);

-		if (trace.allsolid || trace.startsolid ||

-		trace.fraction < clip->trace.fraction)

-		{

-			trace.ent = touch;

-		 	if (clip->trace.startsolid)

-			{

-				clip->trace = trace;

-				clip->trace.startsolid = true;

-			}

-			else

-				clip->trace = trace;

-		}

-		else if (trace.startsolid)

-			clip->trace.startsolid = true;

-	}

-	

-// recurse down both sides

-	if (node->axis == -1)

-		return;

-

-	if ( clip->boxmaxs[node->axis] > node->dist )

-		SV_ClipToLinks ( node->children[0], clip );

-	if ( clip->boxmins[node->axis] < node->dist )

-		SV_ClipToLinks ( node->children[1], clip );

-}

-

-

-/*

-==================

-SV_MoveBounds

-==================

-*/

-void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)

-{

-#if 0

-// debug to test against everything

-boxmins[0] = boxmins[1] = boxmins[2] = -9999;

-boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;

-#else

-	int		i;

-	

-	for (i=0 ; i<3 ; i++)

-	{

-		if (end[i] > start[i])

-		{

-			boxmins[i] = start[i] + mins[i] - 1;

-			boxmaxs[i] = end[i] + maxs[i] + 1;

-		}

-		else

-		{

-			boxmins[i] = end[i] + mins[i] - 1;

-			boxmaxs[i] = start[i] + maxs[i] + 1;

-		}

-	}

-#endif

-}

-

-/*

-==================

-SV_Move

-==================

-*/

-trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)

-{

-	moveclip_t	clip;

-	int			i;

-

-	memset ( &clip, 0, sizeof ( moveclip_t ) );

-

-// clip to world

-	clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end );

-

-	clip.start = start;

-	clip.end = end;

-	clip.mins = mins;

-	clip.maxs = maxs;

-	clip.type = type;

-	clip.passedict = passedict;

-

-	if (type == MOVE_MISSILE)

-	{

-		for (i=0 ; i<3 ; i++)

-		{

-			clip.mins2[i] = -15;

-			clip.maxs2[i] = 15;

-		}

-	}

-	else

-	{

-		VectorCopy (mins, clip.mins2);

-		VectorCopy (maxs, clip.maxs2);

-	}

-	

-// create the bounding box of the entire move

-	SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );

-

-// clip to entities

-	SV_ClipToLinks ( sv_areanodes, &clip );

-

-	return clip.trace;

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// world.c -- world query functions
+
+#include "quakedef.h"
+
+/*
+
+entities never clip against themselves, or their owner
+
+line of sight checks trace->crosscontent, but bullets don't
+
+*/
+
+
+typedef struct
+{
+	vec3_t		boxmins, boxmaxs;// enclose the test object along entire move
+	float		*mins, *maxs;	// size of the moving object
+	vec3_t		mins2, maxs2;	// size when clipping against mosnters
+	float		*start, *end;
+	trace_t		trace;
+	int			type;
+	edict_t		*passedict;
+} moveclip_t;
+
+
+int SV_HullPointContents (hull_t *hull, int num, vec3_t p);
+
+/*
+===============================================================================
+
+HULL BOXES
+
+===============================================================================
+*/
+
+
+static	hull_t		box_hull;
+static	dclipnode_t	box_clipnodes[6];
+static	mplane_t	box_planes[6];
+
+/*
+===================
+SV_InitBoxHull
+
+Set up the planes and clipnodes so that the six floats of a bounding box
+can just be stored out and get a proper hull_t structure.
+===================
+*/
+void SV_InitBoxHull (void)
+{
+	int		i;
+	int		side;
+
+	box_hull.clipnodes = box_clipnodes;
+	box_hull.planes = box_planes;
+	box_hull.firstclipnode = 0;
+	box_hull.lastclipnode = 5;
+
+	for (i=0 ; i<6 ; i++)
+	{
+		box_clipnodes[i].planenum = i;
+		
+		side = i&1;
+		
+		box_clipnodes[i].children[side] = CONTENTS_EMPTY;
+		if (i != 5)
+			box_clipnodes[i].children[side^1] = i + 1;
+		else
+			box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
+		
+		box_planes[i].type = i>>1;
+		box_planes[i].normal[i>>1] = 1;
+	}
+	
+}
+
+
+/*
+===================
+SV_HullForBox
+
+To keep everything totally uniform, bounding boxes are turned into small
+BSP trees instead of being compared directly.
+===================
+*/
+hull_t	*SV_HullForBox (vec3_t mins, vec3_t maxs)
+{
+	box_planes[0].dist = maxs[0];
+	box_planes[1].dist = mins[0];
+	box_planes[2].dist = maxs[1];
+	box_planes[3].dist = mins[1];
+	box_planes[4].dist = maxs[2];
+	box_planes[5].dist = mins[2];
+
+	return &box_hull;
+}
+
+
+
+/*
+================
+SV_HullForEntity
+
+Returns a hull that can be used for testing or clipping an object of mins/maxs
+size.
+Offset is filled in to contain the adjustment that must be added to the
+testing object's origin to get a point to use with the returned hull.
+================
+*/
+hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
+{
+	model_t		*model;
+	vec3_t		size;
+	vec3_t		hullmins, hullmaxs;
+	hull_t		*hull;
+
+// decide which clipping hull to use, based on the size
+	if (ent->u.v.solid == SOLID_BSP)
+	{	// explicit hulls in the BSP model
+		if (ent->u.v.movetype != MOVETYPE_PUSH)
+			Sys_Error ("SOLID_BSP without MOVETYPE_PUSH");
+
+		model = sv.models[ (int)ent->u.v.modelindex ];
+
+		if (!model || model->type != mod_brush)
+			Sys_Error ("MOVETYPE_PUSH with a non bsp model");
+
+		VectorSubtract (maxs, mins, size);
+		if (size[0] < 3)
+			hull = &model->hulls[0];
+		else if (size[0] <= 32)
+			hull = &model->hulls[1];
+		else
+			hull = &model->hulls[2];
+
+// calculate an offset value to center the origin
+		VectorSubtract (hull->clip_mins, mins, offset);
+		VectorAdd (offset, ent->u.v.origin, offset);
+	}
+	else
+	{	// create a temp hull from bounding box sizes
+
+		VectorSubtract (ent->u.v.mins, maxs, hullmins);
+		VectorSubtract (ent->u.v.maxs, mins, hullmaxs);
+		hull = SV_HullForBox (hullmins, hullmaxs);
+		
+		VectorCopy (ent->u.v.origin, offset);
+	}
+
+
+	return hull;
+}
+
+/*
+===============================================================================
+
+ENTITY AREA CHECKING
+
+===============================================================================
+*/
+
+typedef struct areanode_s
+{
+	int		axis;		// -1 = leaf node
+	float	dist;
+	struct areanode_s	*children[2];
+	link_t	trigger_edicts;
+	link_t	solid_edicts;
+} areanode_t;
+
+#define	AREA_DEPTH	4
+#define	AREA_NODES	32
+
+static	areanode_t	sv_areanodes[AREA_NODES];
+static	int			sv_numareanodes;
+
+/*
+===============
+SV_CreateAreaNode
+
+===============
+*/
+areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
+{
+	areanode_t	*anode;
+	vec3_t		size;
+	vec3_t		mins1, maxs1, mins2, maxs2;
+
+	anode = &sv_areanodes[sv_numareanodes];
+	sv_numareanodes++;
+
+	ClearLink (&anode->trigger_edicts);
+	ClearLink (&anode->solid_edicts);
+	
+	if (depth == AREA_DEPTH)
+	{
+		anode->axis = -1;
+		anode->children[0] = anode->children[1] = NULL;
+		return anode;
+	}
+	
+	VectorSubtract (maxs, mins, size);
+	if (size[0] > size[1])
+		anode->axis = 0;
+	else
+		anode->axis = 1;
+	
+	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
+	VectorCopy (mins, mins1);	
+	VectorCopy (mins, mins2);	
+	VectorCopy (maxs, maxs1);	
+	VectorCopy (maxs, maxs2);	
+	
+	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
+	
+	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
+	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
+
+	return anode;
+}
+
+/*
+===============
+SV_ClearWorld
+
+===============
+*/
+void SV_ClearWorld (void)
+{
+	SV_InitBoxHull ();
+	
+	memset (sv_areanodes, 0, sizeof(sv_areanodes));
+	sv_numareanodes = 0;
+	SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);
+}
+
+
+/*
+===============
+SV_UnlinkEdict
+
+===============
+*/
+void SV_UnlinkEdict (edict_t *ent)
+{
+	if (!ent->area.prev)
+		return;		// not linked in anywhere
+	RemoveLink (&ent->area);
+	ent->area.prev = ent->area.next = NULL;
+}
+
+
+/*
+====================
+SV_TouchLinks
+====================
+*/
+void SV_TouchLinks ( edict_t *ent, areanode_t *node )
+{
+	link_t		*l, *next;
+	edict_t		*touch;
+	int			old_self, old_other;
+
+// touch linked edicts
+	for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)
+	{
+		next = l->next;
+		touch = EDICT_FROM_AREA(l);
+		if (touch == ent)
+			continue;
+		if (!touch->u.v.touch || touch->u.v.solid != SOLID_TRIGGER)
+			continue;
+		if (ent->u.v.absmin[0] > touch->u.v.absmax[0]
+		|| ent->u.v.absmin[1] > touch->u.v.absmax[1]
+		|| ent->u.v.absmin[2] > touch->u.v.absmax[2]
+		|| ent->u.v.absmax[0] < touch->u.v.absmin[0]
+		|| ent->u.v.absmax[1] < touch->u.v.absmin[1]
+		|| ent->u.v.absmax[2] < touch->u.v.absmin[2] )
+			continue;
+		old_self = pr_global_struct->self;
+		old_other = pr_global_struct->other;
+
+		pr_global_struct->self = EDICT_TO_PROG(touch);
+		pr_global_struct->other = EDICT_TO_PROG(ent);
+		pr_global_struct->time = sv.time;
+		PR_ExecuteProgram (touch->u.v.touch);
+
+		pr_global_struct->self = old_self;
+		pr_global_struct->other = old_other;
+	}
+	
+// recurse down both sides
+	if (node->axis == -1)
+		return;
+	
+	if ( ent->u.v.absmax[node->axis] > node->dist )
+		SV_TouchLinks ( ent, node->children[0] );
+	if ( ent->u.v.absmin[node->axis] < node->dist )
+		SV_TouchLinks ( ent, node->children[1] );
+}
+
+
+/*
+===============
+SV_FindTouchedLeafs
+
+===============
+*/
+void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
+{
+	mplane_t	*splitplane;
+	mleaf_t		*leaf;
+	int			sides;
+	int			leafnum;
+
+	if (node->contents == CONTENTS_SOLID)
+		return;
+	
+// add an efrag if the node is a leaf
+
+	if ( node->contents < 0)
+	{
+		if (ent->num_leafs == MAX_ENT_LEAFS)
+			return;
+
+		leaf = (mleaf_t *)node;
+		leafnum = leaf - sv.worldmodel->leafs - 1;
+
+		ent->leafnums[ent->num_leafs] = leafnum;
+		ent->num_leafs++;			
+		return;
+	}
+	
+// NODE_MIXED
+
+	splitplane = node->plane;
+	sides = BOX_ON_PLANE_SIDE(ent->u.v.absmin, ent->u.v.absmax, splitplane);
+	
+// recurse down the contacted sides
+	if (sides & 1)
+		SV_FindTouchedLeafs (ent, node->children[0]);
+		
+	if (sides & 2)
+		SV_FindTouchedLeafs (ent, node->children[1]);
+}
+
+/*
+===============
+SV_LinkEdict
+
+===============
+*/
+void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
+{
+	areanode_t	*node;
+
+	if (ent->area.prev)
+		SV_UnlinkEdict (ent);	// unlink from old position
+		
+	if (ent == sv.edicts)
+		return;		// don't add the world
+
+	if (ent->free)
+		return;
+
+// set the abs box
+
+#ifdef QUAKE2
+	if (ent->u.v.solid == SOLID_BSP && 
+	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
+	{	// expand for rotation
+		float		max, v;
+		int			i;
+
+		max = 0;
+		for (i=0 ; i<3 ; i++)
+		{
+			v =fabs( ent->u.v.mins[i]);
+			if (v > max)
+				max = v;
+			v =fabs( ent->u.v.maxs[i]);
+			if (v > max)
+				max = v;
+		}
+		for (i=0 ; i<3 ; i++)
+		{
+			ent->u.v.absmin[i] = ent->u.v.origin[i] - max;
+			ent->u.v.absmax[i] = ent->u.v.origin[i] + max;
+		}
+	}
+	else
+#endif
+	{
+		VectorAdd (ent->u.v.origin, ent->u.v.mins, ent->u.v.absmin);	
+		VectorAdd (ent->u.v.origin, ent->u.v.maxs, ent->u.v.absmax);
+	}
+
+//
+// to make items easier to pick up and allow them to be grabbed off
+// of shelves, the abs sizes are expanded
+//
+	if ((int)ent->u.v.flags & FL_ITEM)
+	{
+		ent->u.v.absmin[0] -= 15;
+		ent->u.v.absmin[1] -= 15;
+		ent->u.v.absmax[0] += 15;
+		ent->u.v.absmax[1] += 15;
+	}
+	else
+	{	// because movement is clipped an epsilon away from an actual edge,
+		// we must fully check even when bounding boxes don't quite touch
+		ent->u.v.absmin[0] -= 1;
+		ent->u.v.absmin[1] -= 1;
+		ent->u.v.absmin[2] -= 1;
+		ent->u.v.absmax[0] += 1;
+		ent->u.v.absmax[1] += 1;
+		ent->u.v.absmax[2] += 1;
+	}
+	
+// link to PVS leafs
+	ent->num_leafs = 0;
+	if (ent->u.v.modelindex)
+		SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
+
+	if (ent->u.v.solid == SOLID_NOT)
+		return;
+
+// find the first node that the ent's box crosses
+	node = sv_areanodes;
+	while (1)
+	{
+		if (node->axis == -1)
+			break;
+		if (ent->u.v.absmin[node->axis] > node->dist)
+			node = node->children[0];
+		else if (ent->u.v.absmax[node->axis] < node->dist)
+			node = node->children[1];
+		else
+			break;		// crosses the node
+	}
+	
+// link it in	
+
+	if (ent->u.v.solid == SOLID_TRIGGER)
+		InsertLinkBefore (&ent->area, &node->trigger_edicts);
+	else
+		InsertLinkBefore (&ent->area, &node->solid_edicts);
+	
+// if touch_triggers, touch all entities at this node and decend for more
+	if (touch_triggers)
+		SV_TouchLinks ( ent, sv_areanodes );
+}
+
+
+
+/*
+===============================================================================
+
+POINT TESTING IN HULLS
+
+===============================================================================
+*/
+
+#if	!id386
+
+/*
+==================
+SV_HullPointContents
+
+==================
+*/
+int SV_HullPointContents (hull_t *hull, int num, vec3_t p)
+{
+	float		d;
+	dclipnode_t	*node;
+	mplane_t	*plane;
+
+	while (num >= 0)
+	{
+		if (num < hull->firstclipnode || num > hull->lastclipnode)
+			Sys_Error ("SV_HullPointContents: bad node number");
+	
+		node = hull->clipnodes + num;
+		plane = hull->planes + node->planenum;
+		
+		if (plane->type < 3)
+			d = p[plane->type] - plane->dist;
+		else
+			d = DotProduct (plane->normal, p) - plane->dist;
+		if (d < 0)
+			num = node->children[1];
+		else
+			num = node->children[0];
+	}
+	
+	return num;
+}
+
+#endif	// !id386
+
+
+/*
+==================
+SV_PointContents
+
+==================
+*/
+int SV_PointContents (vec3_t p)
+{
+	int		cont;
+
+	cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
+	if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
+		cont = CONTENTS_WATER;
+	return cont;
+}
+
+int SV_TruePointContents (vec3_t p)
+{
+	return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
+}
+
+//===========================================================================
+
+/*
+============
+SV_TestEntityPosition
+
+This could be a lot more efficient...
+============
+*/
+edict_t	*SV_TestEntityPosition (edict_t *ent)
+{
+	trace_t	trace;
+
+	trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, ent->u.v.origin, 0, ent);
+	
+	if (trace.startsolid)
+		return sv.edicts;
+		
+	return NULL;
+}
+
+
+/*
+===============================================================================
+
+LINE TESTING IN HULLS
+
+===============================================================================
+*/
+
+// 1/32 epsilon to keep floating point happy
+#define	DIST_EPSILON	(0.03125)
+
+/*
+==================
+SV_RecursiveHullCheck
+
+==================
+*/
+qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
+{
+	dclipnode_t	*node;
+	mplane_t	*plane;
+	float		t1, t2;
+	float		frac;
+	int			i;
+	vec3_t		mid;
+	int			side;
+	float		midf;
+
+// check for empty
+	if (num < 0)
+	{
+		if (num != CONTENTS_SOLID)
+		{
+			trace->allsolid = false;
+			if (num == CONTENTS_EMPTY)
+				trace->inopen = true;
+			else
+				trace->inwater = true;
+		}
+		else
+			trace->startsolid = true;
+		return true;		// empty
+	}
+
+	if (num < hull->firstclipnode || num > hull->lastclipnode)
+		Sys_Error ("SV_RecursiveHullCheck: bad node number");
+
+//
+// find the point distances
+//
+	node = hull->clipnodes + num;
+	plane = hull->planes + node->planenum;
+
+	if (plane->type < 3)
+	{
+		t1 = p1[plane->type] - plane->dist;
+		t2 = p2[plane->type] - plane->dist;
+	}
+	else
+	{
+		t1 = DotProduct (plane->normal, p1) - plane->dist;
+		t2 = DotProduct (plane->normal, p2) - plane->dist;
+	}
+	
+#if 1
+	if (t1 >= 0 && t2 >= 0)
+		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
+	if (t1 < 0 && t2 < 0)
+		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
+#else
+	if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
+		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
+	if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
+		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
+#endif
+
+// put the crosspoint DIST_EPSILON pixels on the near side
+	if (t1 < 0)
+		frac = (t1 + DIST_EPSILON)/(t1-t2);
+	else
+		frac = (t1 - DIST_EPSILON)/(t1-t2);
+	if (frac < 0)
+		frac = 0;
+	if (frac > 1)
+		frac = 1;
+		
+	midf = p1f + (p2f - p1f)*frac;
+	for (i=0 ; i<3 ; i++)
+		mid[i] = p1[i] + frac*(p2[i] - p1[i]);
+
+	side = (t1 < 0);
+
+// move up to the node
+	if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
+		return false;
+
+#ifdef PARANOID
+	if (SV_HullPointContents (sv_hullmodel, mid, node->children[side])
+	== CONTENTS_SOLID)
+	{
+		Con_Printf ("mid PointInHullSolid\n");
+		return false;
+	}
+#endif
+	
+	if (SV_HullPointContents (hull, node->children[side^1], mid)
+	!= CONTENTS_SOLID)
+// go past the node
+		return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
+	
+	if (trace->allsolid)
+		return false;		// never got out of the solid area
+		
+//==================
+// the other side of the node is solid, this is the impact point
+//==================
+	if (!side)
+	{
+		VectorCopy (plane->normal, trace->plane.normal);
+		trace->plane.dist = plane->dist;
+	}
+	else
+	{
+		VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
+		trace->plane.dist = -plane->dist;
+	}
+
+	while (SV_HullPointContents (hull, hull->firstclipnode, mid)
+	== CONTENTS_SOLID)
+	{ // shouldn't really happen, but does occasionally
+		frac -= 0.1;
+		if (frac < 0)
+		{
+			trace->fraction = midf;
+			VectorCopy (mid, trace->endpos);
+			Con_DPrintf ("backup past 0\n");
+			return false;
+		}
+		midf = p1f + (p2f - p1f)*frac;
+		for (i=0 ; i<3 ; i++)
+			mid[i] = p1[i] + frac*(p2[i] - p1[i]);
+	}
+
+	trace->fraction = midf;
+	VectorCopy (mid, trace->endpos);
+
+	return false;
+}
+
+
+/*
+==================
+SV_ClipMoveToEntity
+
+Handles selection or creation of a clipping hull, and offseting (and
+eventually rotation) of the end points
+==================
+*/
+trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+{
+	trace_t		trace;
+	vec3_t		offset;
+	vec3_t		start_l, end_l;
+	hull_t		*hull;
+
+// fill in a default trace
+	memset (&trace, 0, sizeof(trace_t));
+	trace.fraction = 1;
+	trace.allsolid = true;
+	VectorCopy (end, trace.endpos);
+
+// get the clipping hull
+	hull = SV_HullForEntity (ent, mins, maxs, offset);
+
+	VectorSubtract (start, offset, start_l);
+	VectorSubtract (end, offset, end_l);
+
+#ifdef QUAKE2
+	// rotate start and end into the models frame of reference
+	if (ent->u.v.solid == SOLID_BSP && 
+	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
+	{
+		vec3_t	a;
+		vec3_t	forward, right, up;
+		vec3_t	temp;
+
+		AngleVectors (ent->u.v.angles, forward, right, up);
+
+		VectorCopy (start_l, temp);
+		start_l[0] = DotProduct (temp, forward);
+		start_l[1] = -DotProduct (temp, right);
+		start_l[2] = DotProduct (temp, up);
+
+		VectorCopy (end_l, temp);
+		end_l[0] = DotProduct (temp, forward);
+		end_l[1] = -DotProduct (temp, right);
+		end_l[2] = DotProduct (temp, up);
+	}
+#endif
+
+// trace a line through the apropriate clipping hull
+	SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
+
+#ifdef QUAKE2
+	// rotate endpos back to world frame of reference
+	if (ent->u.v.solid == SOLID_BSP && 
+	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
+	{
+		vec3_t	a;
+		vec3_t	forward, right, up;
+		vec3_t	temp;
+
+		if (trace.fraction != 1)
+		{
+			VectorSubtract (vec3_origin, ent->u.v.angles, a);
+			AngleVectors (a, forward, right, up);
+
+			VectorCopy (trace.endpos, temp);
+			trace.endpos[0] = DotProduct (temp, forward);
+			trace.endpos[1] = -DotProduct (temp, right);
+			trace.endpos[2] = DotProduct (temp, up);
+
+			VectorCopy (trace.plane.normal, temp);
+			trace.plane.normal[0] = DotProduct (temp, forward);
+			trace.plane.normal[1] = -DotProduct (temp, right);
+			trace.plane.normal[2] = DotProduct (temp, up);
+		}
+	}
+#endif
+
+// fix trace up by the offset
+	if (trace.fraction != 1)
+		VectorAdd (trace.endpos, offset, trace.endpos);
+
+// did we clip the move?
+	if (trace.fraction < 1 || trace.startsolid  )
+		trace.ent = ent;
+
+	return trace;
+}
+
+//===========================================================================
+
+/*
+====================
+SV_ClipToLinks
+
+Mins and maxs enclose the entire area swept by the move
+====================
+*/
+void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )
+{
+	link_t		*l, *next;
+	edict_t		*touch;
+	trace_t		trace;
+
+// touch linked edicts
+	for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
+	{
+		next = l->next;
+		touch = EDICT_FROM_AREA(l);
+		if (touch->u.v.solid == SOLID_NOT)
+			continue;
+		if (touch == clip->passedict)
+			continue;
+		if (touch->u.v.solid == SOLID_TRIGGER)
+			Sys_Error ("Trigger in clipping list");
+
+		if (clip->type == MOVE_NOMONSTERS && touch->u.v.solid != SOLID_BSP)
+			continue;
+
+		if (clip->boxmins[0] > touch->u.v.absmax[0]
+		|| clip->boxmins[1] > touch->u.v.absmax[1]
+		|| clip->boxmins[2] > touch->u.v.absmax[2]
+		|| clip->boxmaxs[0] < touch->u.v.absmin[0]
+		|| clip->boxmaxs[1] < touch->u.v.absmin[1]
+		|| clip->boxmaxs[2] < touch->u.v.absmin[2] )
+			continue;
+
+		if (clip->passedict && clip->passedict->u.v.size[0] && !touch->u.v.size[0])
+			continue;	// points never interact
+
+	// might intersect, so do an exact clip
+		if (clip->trace.allsolid)
+			return;
+		if (clip->passedict)
+		{
+		 	if (PROG_TO_EDICT(touch->u.v.owner) == clip->passedict)
+				continue;	// don't clip against own missiles
+			if (PROG_TO_EDICT(clip->passedict->u.v.owner) == touch)
+				continue;	// don't clip against owner
+		}
+
+		if ((int)touch->u.v.flags & FL_MONSTER)
+			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);
+		else
+			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
+		if (trace.allsolid || trace.startsolid ||
+		trace.fraction < clip->trace.fraction)
+		{
+			trace.ent = touch;
+		 	if (clip->trace.startsolid)
+			{
+				clip->trace = trace;
+				clip->trace.startsolid = true;
+			}
+			else
+				clip->trace = trace;
+		}
+		else if (trace.startsolid)
+			clip->trace.startsolid = true;
+	}
+	
+// recurse down both sides
+	if (node->axis == -1)
+		return;
+
+	if ( clip->boxmaxs[node->axis] > node->dist )
+		SV_ClipToLinks ( node->children[0], clip );
+	if ( clip->boxmins[node->axis] < node->dist )
+		SV_ClipToLinks ( node->children[1], clip );
+}
+
+
+/*
+==================
+SV_MoveBounds
+==================
+*/
+void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
+{
+#if 0
+// debug to test against everything
+boxmins[0] = boxmins[1] = boxmins[2] = -9999;
+boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
+#else
+	int		i;
+	
+	for (i=0 ; i<3 ; i++)
+	{
+		if (end[i] > start[i])
+		{
+			boxmins[i] = start[i] + mins[i] - 1;
+			boxmaxs[i] = end[i] + maxs[i] + 1;
+		}
+		else
+		{
+			boxmins[i] = end[i] + mins[i] - 1;
+			boxmaxs[i] = start[i] + maxs[i] + 1;
+		}
+	}
+#endif
+}
+
+/*
+==================
+SV_Move
+==================
+*/
+trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)
+{
+	moveclip_t	clip;
+	int			i;
+
+	memset ( &clip, 0, sizeof ( moveclip_t ) );
+
+// clip to world
+	clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end );
+
+	clip.start = start;
+	clip.end = end;
+	clip.mins = mins;
+	clip.maxs = maxs;
+	clip.type = type;
+	clip.passedict = passedict;
+
+	if (type == MOVE_MISSILE)
+	{
+		for (i=0 ; i<3 ; i++)
+		{
+			clip.mins2[i] = -15;
+			clip.maxs2[i] = 15;
+		}
+	}
+	else
+	{
+		VectorCopy (mins, clip.mins2);
+		VectorCopy (maxs, clip.maxs2);
+	}
+	
+// create the bounding box of the entire move
+	SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
+
+// clip to entities
+	SV_ClipToLinks ( sv_areanodes, &clip );
+
+	return clip.trace;
+}
+
diff --git a/quake/src/WinQuake/wq.bat b/quake/src/WinQuake/wq.bat
old mode 100755
new mode 100644
diff --git a/quake/src/WinQuake/zone.c b/quake/src/WinQuake/zone.cpp
old mode 100644
new mode 100755
similarity index 90%
rename from quake/src/WinQuake/zone.c
rename to quake/src/WinQuake/zone.cpp
index 42d7c45..b372da5
--- a/quake/src/WinQuake/zone.c
+++ b/quake/src/WinQuake/zone.cpp
@@ -1,935 +1,935 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-// Z_zone.c

-

-#include "quakedef.h"

-

-#define	DYNAMIC_SIZE	0xc000

-

-#define	ZONEID	0x1d4a11

-#define MINFRAGMENT	64

-

-typedef struct memblock_s

-{

-	int		size;           // including the header and possibly tiny fragments

-	int     tag;            // a tag of 0 is a free block

-	int     id;        		// should be ZONEID

-	struct memblock_s       *next, *prev;

-	int		pad;			// pad to 64 bit boundary

-} memblock_t;

-

-typedef struct

-{

-	int		size;		// total bytes malloced, including header

-	memblock_t	blocklist;		// start / end cap for linked list

-	memblock_t	*rover;

-} memzone_t;

-

-void Cache_FreeLow (int new_low_hunk);

-void Cache_FreeHigh (int new_high_hunk);

-

-

-/*

-==============================================================================

-

-						ZONE MEMORY ALLOCATION

-

-There is never any space between memblocks, and there will never be two

-contiguous free memblocks.

-

-The rover can be left pointing at a non-empty block

-

-The zone calls are pretty much only used for small strings and structures,

-all big things are allocated on the hunk.

-==============================================================================

-*/

-

-memzone_t	*mainzone;

-

-void Z_ClearZone (memzone_t *zone, int size);

-

-

-/*

-========================

-Z_ClearZone

-========================

-*/

-void Z_ClearZone (memzone_t *zone, int size)

-{

-	memblock_t	*block;

-	

-// set the entire zone to one free block

-

-	zone->blocklist.next = zone->blocklist.prev = block =

-		(memblock_t *)( (byte *)zone + sizeof(memzone_t) );

-	zone->blocklist.tag = 1;	// in use block

-	zone->blocklist.id = 0;

-	zone->blocklist.size = 0;

-	zone->rover = block;

-	

-	block->prev = block->next = &zone->blocklist;

-	block->tag = 0;			// free block

-	block->id = ZONEID;

-	block->size = size - sizeof(memzone_t);

-}

-

-

-/*

-========================

-Z_Free

-========================

-*/

-void Z_Free (void *ptr)

-{

-	memblock_t	*block, *other;

-	

-	if (!ptr)

-		Sys_Error ("Z_Free: NULL pointer");

-

-	block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));

-	if (block->id != ZONEID)

-		Sys_Error ("Z_Free: freed a pointer without ZONEID");

-	if (block->tag == 0)

-		Sys_Error ("Z_Free: freed a freed pointer");

-

-	block->tag = 0;		// mark as free

-	

-	other = block->prev;

-	if (!other->tag)

-	{	// merge with previous free block

-		other->size += block->size;

-		other->next = block->next;

-		other->next->prev = other;

-		if (block == mainzone->rover)

-			mainzone->rover = other;

-		block = other;

-	}

-	

-	other = block->next;

-	if (!other->tag)

-	{	// merge the next free block onto the end

-		block->size += other->size;

-		block->next = other->next;

-		block->next->prev = block;

-		if (other == mainzone->rover)

-			mainzone->rover = block;

-	}

-}

-

-

-/*

-========================

-Z_Malloc

-========================

-*/

-void *Z_Malloc (int size)

-{

-	void	*buf;

-	

-Z_CheckHeap ();	// DEBUG

-	buf = Z_TagMalloc (size, 1);

-	if (!buf)

-		Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size);

-	Q_memset (buf, 0, size);

-

-	return buf;

-}

-

-void *Z_TagMalloc (int size, int tag)

-{

-	int		extra;

-	memblock_t	*start, *rover, *new, *base;

-

-	if (!tag)

-		Sys_Error ("Z_TagMalloc: tried to use a 0 tag");

-

-//

-// scan through the block list looking for the first free block

-// of sufficient size

-//

-	size += sizeof(memblock_t);	// account for size of block header

-	size += 4;					// space for memory trash tester

-	size = (size + 7) & ~7;		// align to 8-byte boundary

-	

-	base = rover = mainzone->rover;

-	start = base->prev;

-	

-	do

-	{

-		if (rover == start)	// scaned all the way around the list

-			return NULL;

-		if (rover->tag)

-			base = rover = rover->next;

-		else

-			rover = rover->next;

-	} while (base->tag || base->size < size);

-	

-//

-// found a block big enough

-//

-	extra = base->size - size;

-	if (extra >  MINFRAGMENT)

-	{	// there will be a free fragment after the allocated block

-		new = (memblock_t *) ((byte *)base + size );

-		new->size = extra;

-		new->tag = 0;			// free block

-		new->prev = base;

-		new->id = ZONEID;

-		new->next = base->next;

-		new->next->prev = new;

-		base->next = new;

-		base->size = size;

-	}

-	

-	base->tag = tag;				// no longer a free block

-	

-	mainzone->rover = base->next;	// next allocation will start looking here

-	

-	base->id = ZONEID;

-

-// marker for memory trash testing

-	*(int *)((byte *)base + base->size - 4) = ZONEID;

-

-	return (void *) ((byte *)base + sizeof(memblock_t));

-}

-

-

-/*

-========================

-Z_Print

-========================

-*/

-void Z_Print (memzone_t *zone)

-{

-	memblock_t	*block;

-	

-	Con_Printf ("zone size: %i  location: %p\n",mainzone->size,mainzone);

-	

-	for (block = zone->blocklist.next ; ; block = block->next)

-	{

-		Con_Printf ("block:%p    size:%7i    tag:%3i\n",

-			block, block->size, block->tag);

-		

-		if (block->next == &zone->blocklist)

-			break;			// all blocks have been hit	

-		if ( (byte *)block + block->size != (byte *)block->next)

-			Con_Printf ("ERROR: block size does not touch the next block\n");

-		if ( block->next->prev != block)

-			Con_Printf ("ERROR: next block doesn't have proper back link\n");

-		if (!block->tag && !block->next->tag)

-			Con_Printf ("ERROR: two consecutive free blocks\n");

-	}

-}

-

-

-/*

-========================

-Z_CheckHeap

-========================

-*/

-void Z_CheckHeap (void)

-{

-	memblock_t	*block;

-	

-	for (block = mainzone->blocklist.next ; ; block = block->next)

-	{

-		if (block->next == &mainzone->blocklist)

-			break;			// all blocks have been hit	

-		if ( (byte *)block + block->size != (byte *)block->next)

-			Sys_Error ("Z_CheckHeap: block size does not touch the next block\n");

-		if ( block->next->prev != block)

-			Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n");

-		if (!block->tag && !block->next->tag)

-			Sys_Error ("Z_CheckHeap: two consecutive free blocks\n");

-	}

-}

-

-//============================================================================

-

-#define	HUNK_SENTINAL	0x1df001ed

-

-typedef struct

-{

-	int		sentinal;

-	int		size;		// including sizeof(hunk_t), -1 = not allocated

-	char	name[8];

-} hunk_t;

-

-byte	*hunk_base;

-int		hunk_size;

-

-int		hunk_low_used;

-int		hunk_high_used;

-

-qboolean	hunk_tempactive;

-int		hunk_tempmark;

-

-void R_FreeTextures (void);

-

-/*

-==============

-Hunk_Check

-

-Run consistancy and sentinal trahing checks

-==============

-*/

-void Hunk_Check (void)

-{

-	hunk_t	*h;

-	

-	for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; )

-	{

-		if (h->sentinal != HUNK_SENTINAL)

-			Sys_Error ("Hunk_Check: trahsed sentinal");

-		if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)

-			Sys_Error ("Hunk_Check: bad size");

-		h = (hunk_t *)((byte *)h+h->size);

-	}

-}

-

-/*

-==============

-Hunk_Print

-

-If "all" is specified, every single allocation is printed.

-Otherwise, allocations with the same name will be totaled up before printing.

-==============

-*/

-void Hunk_Print (qboolean all)

-{

-	hunk_t	*h, *next, *endlow, *starthigh, *endhigh;

-	int		count, sum;

-	int		totalblocks;

-	char	name[9];

-

-	name[8] = 0;

-	count = 0;

-	sum = 0;

-	totalblocks = 0;

-	

-	h = (hunk_t *)hunk_base;

-	endlow = (hunk_t *)(hunk_base + hunk_low_used);

-	starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);

-	endhigh = (hunk_t *)(hunk_base + hunk_size);

-

-	Con_Printf ("          :%8i total hunk size\n", hunk_size);

-	Con_Printf ("-------------------------\n");

-

-	while (1)

-	{

-	//

-	// skip to the high hunk if done with low hunk

-	//

-		if ( h == endlow )

-		{

-			Con_Printf ("-------------------------\n");

-			Con_Printf ("          :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used);

-			Con_Printf ("-------------------------\n");

-			h = starthigh;

-		}

-		

-	//

-	// if totally done, break

-	//

-		if ( h == endhigh )

-			break;

-

-	//

-	// run consistancy checks

-	//

-		if (h->sentinal != HUNK_SENTINAL)

-			Sys_Error ("Hunk_Check: trahsed sentinal");

-		if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)

-			Sys_Error ("Hunk_Check: bad size");

-			

-		next = (hunk_t *)((byte *)h+h->size);

-		count++;

-		totalblocks++;

-		sum += h->size;

-

-	//

-	// print the single block

-	//

-		memcpy (name, h->name, 8);

-		if (all)

-			Con_Printf ("%8p :%8i %8s\n",h, h->size, name);

-			

-	//

-	// print the total

-	//

-		if (next == endlow || next == endhigh || 

-		strncmp (h->name, next->name, 8) )

-		{

-			if (!all)

-				Con_Printf ("          :%8i %8s (TOTAL)\n",sum, name);

-			count = 0;

-			sum = 0;

-		}

-

-		h = next;

-	}

-

-	Con_Printf ("-------------------------\n");

-	Con_Printf ("%8i total blocks\n", totalblocks);

-	

-}

-

-/*

-===================

-Hunk_AllocName

-===================

-*/

-void *Hunk_AllocName (int size, char *name)

-{

-	hunk_t	*h;

-	

-#ifdef PARANOID

-	Hunk_Check ();

-#endif

-

-	if (size < 0)

-		Sys_Error ("Hunk_Alloc: bad size: %i", size);

-		

-	size = sizeof(hunk_t) + ((size+15)&~15);

-	

-	if (hunk_size - hunk_low_used - hunk_high_used < size)

-		Sys_Error ("Hunk_Alloc: failed on %i bytes",size);

-	

-	h = (hunk_t *)(hunk_base + hunk_low_used);

-	hunk_low_used += size;

-

-	Cache_FreeLow (hunk_low_used);

-

-	memset (h, 0, size);

-	

-	h->size = size;

-	h->sentinal = HUNK_SENTINAL;

-	Q_strncpy (h->name, name, 8);

-	

-	return (void *)(h+1);

-}

-

-/*

-===================

-Hunk_Alloc

-===================

-*/

-void *Hunk_Alloc (int size)

-{

-	return Hunk_AllocName (size, "unknown");

-}

-

-int	Hunk_LowMark (void)

-{

-	return hunk_low_used;

-}

-

-void Hunk_FreeToLowMark (int mark)

-{

-	if (mark < 0 || mark > hunk_low_used)

-		Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);

-	memset (hunk_base + mark, 0, hunk_low_used - mark);

-	hunk_low_used = mark;

-}

-

-int	Hunk_HighMark (void)

-{

-	if (hunk_tempactive)

-	{

-		hunk_tempactive = false;

-		Hunk_FreeToHighMark (hunk_tempmark);

-	}

-

-	return hunk_high_used;

-}

-

-void Hunk_FreeToHighMark (int mark)

-{

-	if (hunk_tempactive)

-	{

-		hunk_tempactive = false;

-		Hunk_FreeToHighMark (hunk_tempmark);

-	}

-	if (mark < 0 || mark > hunk_high_used)

-		Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);

-	memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);

-	hunk_high_used = mark;

-}

-

-

-/*

-===================

-Hunk_HighAllocName

-===================

-*/

-void *Hunk_HighAllocName (int size, char *name)

-{

-	hunk_t	*h;

-

-	if (size < 0)

-		Sys_Error ("Hunk_HighAllocName: bad size: %i", size);

-

-	if (hunk_tempactive)

-	{

-		Hunk_FreeToHighMark (hunk_tempmark);

-		hunk_tempactive = false;

-	}

-

-#ifdef PARANOID

-	Hunk_Check ();

-#endif

-

-	size = sizeof(hunk_t) + ((size+15)&~15);

-

-	if (hunk_size - hunk_low_used - hunk_high_used < size)

-	{

-		Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);

-		return NULL;

-	}

-

-	hunk_high_used += size;

-	Cache_FreeHigh (hunk_high_used);

-

-	h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);

-

-	memset (h, 0, size);

-	h->size = size;

-	h->sentinal = HUNK_SENTINAL;

-	Q_strncpy (h->name, name, 8);

-

-	return (void *)(h+1);

-}

-

-

-/*

-=================

-Hunk_TempAlloc

-

-Return space from the top of the hunk

-=================

-*/

-void *Hunk_TempAlloc (int size)

-{

-	void	*buf;

-

-	size = (size+15)&~15;

-	

-	if (hunk_tempactive)

-	{

-		Hunk_FreeToHighMark (hunk_tempmark);

-		hunk_tempactive = false;

-	}

-	

-	hunk_tempmark = Hunk_HighMark ();

-

-	buf = Hunk_HighAllocName (size, "temp");

-

-	hunk_tempactive = true;

-

-	return buf;

-}

-

-/*

-===============================================================================

-

-CACHE MEMORY

-

-===============================================================================

-*/

-

-typedef struct cache_system_s

-{

-	int						size;		// including this header

-	cache_user_t			*user;

-	char					name[16];

-	struct cache_system_s	*prev, *next;

-	struct cache_system_s	*lru_prev, *lru_next;	// for LRU flushing	

-} cache_system_t;

-

-cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);

-

-cache_system_t	cache_head;

-

-/*

-===========

-Cache_Move

-===========

-*/

-void Cache_Move ( cache_system_t *c)

-{

-	cache_system_t		*new;

-

-// we are clearing up space at the bottom, so only allocate it late

-	new = Cache_TryAlloc (c->size, true);

-	if (new)

-	{

-//		Con_Printf ("cache_move ok\n");

-

-		Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) );

-		new->user = c->user;

-		Q_memcpy (new->name, c->name, sizeof(new->name));

-		Cache_Free (c->user);

-		new->user->data = (void *)(new+1);

-	}

-	else

-	{

-//		Con_Printf ("cache_move failed\n");

-

-		Cache_Free (c->user);		// tough luck...

-	}

-}

-

-/*

-============

-Cache_FreeLow

-

-Throw things out until the hunk can be expanded to the given point

-============

-*/

-void Cache_FreeLow (int new_low_hunk)

-{

-	cache_system_t	*c;

-	

-	while (1)

-	{

-		c = cache_head.next;

-		if (c == &cache_head)

-			return;		// nothing in cache at all

-		if ((byte *)c >= hunk_base + new_low_hunk)

-			return;		// there is space to grow the hunk

-		Cache_Move ( c );	// reclaim the space

-	}

-}

-

-/*

-============

-Cache_FreeHigh

-

-Throw things out until the hunk can be expanded to the given point

-============

-*/

-void Cache_FreeHigh (int new_high_hunk)

-{

-	cache_system_t	*c, *prev;

-	

-	prev = NULL;

-	while (1)

-	{

-		c = cache_head.prev;

-		if (c == &cache_head)

-			return;		// nothing in cache at all

-		if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)

-			return;		// there is space to grow the hunk

-		if (c == prev)

-			Cache_Free (c->user);	// didn't move out of the way

-		else

-		{

-			Cache_Move (c);	// try to move it

-			prev = c;

-		}

-	}

-}

-

-void Cache_UnlinkLRU (cache_system_t *cs)

-{

-	if (!cs->lru_next || !cs->lru_prev)

-		Sys_Error ("Cache_UnlinkLRU: NULL link");

-

-	cs->lru_next->lru_prev = cs->lru_prev;

-	cs->lru_prev->lru_next = cs->lru_next;

-	

-	cs->lru_prev = cs->lru_next = NULL;

-}

-

-void Cache_MakeLRU (cache_system_t *cs)

-{

-	if (cs->lru_next || cs->lru_prev)

-		Sys_Error ("Cache_MakeLRU: active link");

-

-	cache_head.lru_next->lru_prev = cs;

-	cs->lru_next = cache_head.lru_next;

-	cs->lru_prev = &cache_head;

-	cache_head.lru_next = cs;

-}

-

-/*

-============

-Cache_TryAlloc

-

-Looks for a free block of memory between the high and low hunk marks

-Size should already include the header and padding

-============

-*/

-cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)

-{

-	cache_system_t	*cs, *new;

-	

-// is the cache completely empty?

-

-	if (!nobottom && cache_head.prev == &cache_head)

-	{

-		if (hunk_size - hunk_high_used - hunk_low_used < size)

-			Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);

-

-		new = (cache_system_t *) (hunk_base + hunk_low_used);

-		memset (new, 0, sizeof(*new));

-		new->size = size;

-

-		cache_head.prev = cache_head.next = new;

-		new->prev = new->next = &cache_head;

-		

-		Cache_MakeLRU (new);

-		return new;

-	}

-	

-// search from the bottom up for space

-

-	new = (cache_system_t *) (hunk_base + hunk_low_used);

-	cs = cache_head.next;

-	

-	do

-	{

-		if (!nobottom || cs != cache_head.next)

-		{

-			if ( (byte *)cs - (byte *)new >= size)

-			{	// found space

-				memset (new, 0, sizeof(*new));

-				new->size = size;

-				

-				new->next = cs;

-				new->prev = cs->prev;

-				cs->prev->next = new;

-				cs->prev = new;

-				

-				Cache_MakeLRU (new);

-	

-				return new;

-			}

-		}

-

-	// continue looking		

-		new = (cache_system_t *)((byte *)cs + cs->size);

-		cs = cs->next;

-

-	} while (cs != &cache_head);

-	

-// try to allocate one at the very end

-	if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size)

-	{

-		memset (new, 0, sizeof(*new));

-		new->size = size;

-		

-		new->next = &cache_head;

-		new->prev = cache_head.prev;

-		cache_head.prev->next = new;

-		cache_head.prev = new;

-		

-		Cache_MakeLRU (new);

-

-		return new;

-	}

-	

-	return NULL;		// couldn't allocate

-}

-

-/*

-============

-Cache_Flush

-

-Throw everything out, so new data will be demand cached

-============

-*/

-void Cache_Flush (void)

-{

-	while (cache_head.next != &cache_head)

-		Cache_Free ( cache_head.next->user );	// reclaim the space

-}

-

-

-/*

-============

-Cache_Print

-

-============

-*/

-void Cache_Print (void)

-{

-	cache_system_t	*cd;

-

-	for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)

-	{

-		Con_Printf ("%8i : %s\n", cd->size, cd->name);

-	}

-}

-

-/*

-============

-Cache_Report

-

-============

-*/

-void Cache_Report (void)

-{

-	Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );

-}

-

-/*

-============

-Cache_Compact

-

-============

-*/

-void Cache_Compact (void)

-{

-}

-

-/*

-============

-Cache_Init

-

-============

-*/

-void Cache_Init (void)

-{

-	cache_head.next = cache_head.prev = &cache_head;

-	cache_head.lru_next = cache_head.lru_prev = &cache_head;

-

-	Cmd_AddCommand ("flush", Cache_Flush);

-}

-

-/*

-==============

-Cache_Free

-

-Frees the memory and removes it from the LRU list

-==============

-*/

-void Cache_Free (cache_user_t *c)

-{

-	cache_system_t	*cs;

-

-	if (!c->data)

-		Sys_Error ("Cache_Free: not allocated");

-

-	cs = ((cache_system_t *)c->data) - 1;

-

-	cs->prev->next = cs->next;

-	cs->next->prev = cs->prev;

-	cs->next = cs->prev = NULL;

-

-	c->data = NULL;

-

-	Cache_UnlinkLRU (cs);

-}

-

-

-

-/*

-==============

-Cache_Check

-==============

-*/

-void *Cache_Check (cache_user_t *c)

-{

-	cache_system_t	*cs;

-

-	if (!c->data)

-		return NULL;

-

-	cs = ((cache_system_t *)c->data) - 1;

-

-// move to head of LRU

-	Cache_UnlinkLRU (cs);

-	Cache_MakeLRU (cs);

-	

-	return c->data;

-}

-

-

-/*

-==============

-Cache_Alloc

-==============

-*/

-void *Cache_Alloc (cache_user_t *c, int size, char *name)

-{

-	cache_system_t	*cs;

-

-	if (c->data)

-		Sys_Error ("Cache_Alloc: allready allocated");

-	

-	if (size <= 0)

-		Sys_Error ("Cache_Alloc: size %i", size);

-

-	size = (size + sizeof(cache_system_t) + 15) & ~15;

-

-// find memory for it	

-	while (1)

-	{

-		cs = Cache_TryAlloc (size, false);

-		if (cs)

-		{

-			strncpy (cs->name, name, sizeof(cs->name)-1);

-			c->data = (void *)(cs+1);

-			cs->user = c;

-			break;

-		}

-	

-	// free the least recently used cahedat

-		if (cache_head.lru_prev == &cache_head)

-			Sys_Error ("Cache_Alloc: out of memory");

-													// not enough memory at all

-		Cache_Free ( cache_head.lru_prev->user );

-	} 

-	

-	return Cache_Check (c);

-}

-

-//============================================================================

-

-

-/*

-========================

-Memory_Init

-========================

-*/

-void Memory_Init (void *buf, int size)

-{

-	int p;

-	int zonesize = DYNAMIC_SIZE;

-

-	hunk_base = buf;

-	hunk_size = size;

-	hunk_low_used = 0;

-	hunk_high_used = 0;

-	

-	Cache_Init ();

-	p = COM_CheckParm ("-zone");

-	if (p)

-	{

-		if (p < com_argc-1)

-			zonesize = Q_atoi (com_argv[p+1]) * 1024;

-		else

-			Sys_Error ("Memory_Init: you must specify a size in KB after -zone");

-	}

-	mainzone = Hunk_AllocName (zonesize, "zone" );

-	Z_ClearZone (mainzone, zonesize);

-}

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// Z_zone.c
+
+#include "quakedef.h"
+
+#define	DYNAMIC_SIZE	0xc000
+
+#define	ZONEID	0x1d4a11
+#define MINFRAGMENT	64
+
+typedef struct memblock_s
+{
+	int		size;           // including the header and possibly tiny fragments
+	int     tag;            // a tag of 0 is a free block
+	int     id;        		// should be ZONEID
+	struct memblock_s       *next, *prev;
+	int		pad;			// pad to 64 bit boundary
+} memblock_t;
+
+typedef struct
+{
+	int		size;		// total bytes malloced, including header
+	memblock_t	blocklist;		// start / end cap for linked list
+	memblock_t	*rover;
+} memzone_t;
+
+void Cache_FreeLow (int new_low_hunk);
+void Cache_FreeHigh (int new_high_hunk);
+
+
+/*
+==============================================================================
+
+						ZONE MEMORY ALLOCATION
+
+There is never any space between memblocks, and there will never be two
+contiguous free memblocks.
+
+The rover can be left pointing at a non-empty block
+
+The zone calls are pretty much only used for small strings and structures,
+all big things are allocated on the hunk.
+==============================================================================
+*/
+
+memzone_t	*mainzone;
+
+void Z_ClearZone (memzone_t *zone, int size);
+
+
+/*
+========================
+Z_ClearZone
+========================
+*/
+void Z_ClearZone (memzone_t *zone, int size)
+{
+	memblock_t	*block;
+	
+// set the entire zone to one free block
+
+	zone->blocklist.next = zone->blocklist.prev = block =
+		(memblock_t *)( (byte *)zone + sizeof(memzone_t) );
+	zone->blocklist.tag = 1;	// in use block
+	zone->blocklist.id = 0;
+	zone->blocklist.size = 0;
+	zone->rover = block;
+	
+	block->prev = block->next = &zone->blocklist;
+	block->tag = 0;			// free block
+	block->id = ZONEID;
+	block->size = size - sizeof(memzone_t);
+}
+
+
+/*
+========================
+Z_Free
+========================
+*/
+void Z_Free (void *ptr)
+{
+	memblock_t	*block, *other;
+	
+	if (!ptr)
+		Sys_Error ("Z_Free: NULL pointer");
+
+	block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+	if (block->id != ZONEID)
+		Sys_Error ("Z_Free: freed a pointer without ZONEID");
+	if (block->tag == 0)
+		Sys_Error ("Z_Free: freed a freed pointer");
+
+	block->tag = 0;		// mark as free
+	
+	other = block->prev;
+	if (!other->tag)
+	{	// merge with previous free block
+		other->size += block->size;
+		other->next = block->next;
+		other->next->prev = other;
+		if (block == mainzone->rover)
+			mainzone->rover = other;
+		block = other;
+	}
+	
+	other = block->next;
+	if (!other->tag)
+	{	// merge the next free block onto the end
+		block->size += other->size;
+		block->next = other->next;
+		block->next->prev = block;
+		if (other == mainzone->rover)
+			mainzone->rover = block;
+	}
+}
+
+
+/*
+========================
+Z_Malloc
+========================
+*/
+void *Z_Malloc (int size)
+{
+	void	*buf;
+	
+Z_CheckHeap ();	// DEBUG
+	buf = Z_TagMalloc (size, 1);
+	if (!buf)
+		Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size);
+	Q_memset (buf, 0, size);
+
+	return buf;
+}
+
+void *Z_TagMalloc (int size, int tag)
+{
+	int		extra;
+	memblock_t	*start, *rover, *newm, *base;
+
+	if (!tag)
+		Sys_Error ("Z_TagMalloc: tried to use a 0 tag");
+
+//
+// scan through the block list looking for the first free block
+// of sufficient size
+//
+	size += sizeof(memblock_t);	// account for size of block header
+	size += 4;					// space for memory trash tester
+	size = (size + 7) & ~7;		// align to 8-byte boundary
+	
+	base = rover = mainzone->rover;
+	start = base->prev;
+	
+	do
+	{
+		if (rover == start)	// scaned all the way around the list
+			return NULL;
+		if (rover->tag)
+			base = rover = rover->next;
+		else
+			rover = rover->next;
+	} while (base->tag || base->size < size);
+	
+//
+// found a block big enough
+//
+	extra = base->size - size;
+	if (extra >  MINFRAGMENT)
+	{	// there will be a free fragment after the allocated block
+		newm = (memblock_t *) ((byte *)base + size );
+		newm->size = extra;
+		newm->tag = 0;			// free block
+		newm->prev = base;
+		newm->id = ZONEID;
+		newm->next = base->next;
+		newm->next->prev = newm;
+		base->next = newm;
+		base->size = size;
+	}
+	
+	base->tag = tag;				// no longer a free block
+	
+	mainzone->rover = base->next;	// next allocation will start looking here
+	
+	base->id = ZONEID;
+
+// marker for memory trash testing
+	*(int *)((byte *)base + base->size - 4) = ZONEID;
+
+	return (void *) ((byte *)base + sizeof(memblock_t));
+}
+
+
+/*
+========================
+Z_Print
+========================
+*/
+void Z_Print (memzone_t *zone)
+{
+	memblock_t	*block;
+	
+	Con_Printf ("zone size: %i  location: %p\n",mainzone->size,mainzone);
+	
+	for (block = zone->blocklist.next ; ; block = block->next)
+	{
+		Con_Printf ("block:%p    size:%7i    tag:%3i\n",
+			block, block->size, block->tag);
+		
+		if (block->next == &zone->blocklist)
+			break;			// all blocks have been hit	
+		if ( (byte *)block + block->size != (byte *)block->next)
+			Con_Printf ("ERROR: block size does not touch the next block\n");
+		if ( block->next->prev != block)
+			Con_Printf ("ERROR: next block doesn't have proper back link\n");
+		if (!block->tag && !block->next->tag)
+			Con_Printf ("ERROR: two consecutive free blocks\n");
+	}
+}
+
+
+/*
+========================
+Z_CheckHeap
+========================
+*/
+void Z_CheckHeap (void)
+{
+	memblock_t	*block;
+	
+	for (block = mainzone->blocklist.next ; ; block = block->next)
+	{
+		if (block->next == &mainzone->blocklist)
+			break;			// all blocks have been hit	
+		if ( (byte *)block + block->size != (byte *)block->next)
+			Sys_Error ("Z_CheckHeap: block size does not touch the next block\n");
+		if ( block->next->prev != block)
+			Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
+		if (!block->tag && !block->next->tag)
+			Sys_Error ("Z_CheckHeap: two consecutive free blocks\n");
+	}
+}
+
+//============================================================================
+
+#define	HUNK_SENTINAL	0x1df001ed
+
+typedef struct
+{
+	int		sentinal;
+	int		size;		// including sizeof(hunk_t), -1 = not allocated
+	char	name[8];
+} hunk_t;
+
+byte	*hunk_base;
+int		hunk_size;
+
+int		hunk_low_used;
+int		hunk_high_used;
+
+qboolean	hunk_tempactive;
+int		hunk_tempmark;
+
+void R_FreeTextures (void);
+
+/*
+==============
+Hunk_Check
+
+Run consistancy and sentinal trahing checks
+==============
+*/
+void Hunk_Check (void)
+{
+	hunk_t	*h;
+	
+	for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; )
+	{
+		if (h->sentinal != HUNK_SENTINAL)
+			Sys_Error ("Hunk_Check: trahsed sentinal");
+		if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
+			Sys_Error ("Hunk_Check: bad size");
+		h = (hunk_t *)((byte *)h+h->size);
+	}
+}
+
+/*
+==============
+Hunk_Print
+
+If "all" is specified, every single allocation is printed.
+Otherwise, allocations with the same name will be totaled up before printing.
+==============
+*/
+void Hunk_Print (qboolean all)
+{
+	hunk_t	*h, *next, *endlow, *starthigh, *endhigh;
+	int		count, sum;
+	int		totalblocks;
+	char	name[9];
+
+	name[8] = 0;
+	count = 0;
+	sum = 0;
+	totalblocks = 0;
+	
+	h = (hunk_t *)hunk_base;
+	endlow = (hunk_t *)(hunk_base + hunk_low_used);
+	starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
+	endhigh = (hunk_t *)(hunk_base + hunk_size);
+
+	Con_Printf ("          :%8i total hunk size\n", hunk_size);
+	Con_Printf ("-------------------------\n");
+
+	while (1)
+	{
+	//
+	// skip to the high hunk if done with low hunk
+	//
+		if ( h == endlow )
+		{
+			Con_Printf ("-------------------------\n");
+			Con_Printf ("          :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used);
+			Con_Printf ("-------------------------\n");
+			h = starthigh;
+		}
+		
+	//
+	// if totally done, break
+	//
+		if ( h == endhigh )
+			break;
+
+	//
+	// run consistancy checks
+	//
+		if (h->sentinal != HUNK_SENTINAL)
+			Sys_Error ("Hunk_Check: trahsed sentinal");
+		if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
+			Sys_Error ("Hunk_Check: bad size");
+			
+		next = (hunk_t *)((byte *)h+h->size);
+		count++;
+		totalblocks++;
+		sum += h->size;
+
+	//
+	// print the single block
+	//
+		memcpy (name, h->name, 8);
+		if (all)
+			Con_Printf ("%8p :%8i %8s\n",h, h->size, name);
+			
+	//
+	// print the total
+	//
+		if (next == endlow || next == endhigh || 
+		strncmp (h->name, next->name, 8) )
+		{
+			if (!all)
+				Con_Printf ("          :%8i %8s (TOTAL)\n",sum, name);
+			count = 0;
+			sum = 0;
+		}
+
+		h = next;
+	}
+
+	Con_Printf ("-------------------------\n");
+	Con_Printf ("%8i total blocks\n", totalblocks);
+	
+}
+
+/*
+===================
+Hunk_AllocName
+===================
+*/
+void *Hunk_AllocName (int size, const char *name)
+{
+	hunk_t	*h;
+	
+#ifdef PARANOID
+	Hunk_Check ();
+#endif
+
+	if (size < 0)
+		Sys_Error ("Hunk_Alloc: bad size: %i", size);
+		
+	size = sizeof(hunk_t) + ((size+15)&~15);
+	
+	if (hunk_size - hunk_low_used - hunk_high_used < size)
+		Sys_Error ("Hunk_Alloc: failed on %i bytes",size);
+	
+	h = (hunk_t *)(hunk_base + hunk_low_used);
+	hunk_low_used += size;
+
+	Cache_FreeLow (hunk_low_used);
+
+	memset (h, 0, size);
+	
+	h->size = size;
+	h->sentinal = HUNK_SENTINAL;
+	Q_strncpy (h->name, name, 8);
+	
+	return (void *)(h+1);
+}
+
+/*
+===================
+Hunk_Alloc
+===================
+*/
+void *Hunk_Alloc (int size)
+{
+	return Hunk_AllocName (size, "unknown");
+}
+
+int	Hunk_LowMark (void)
+{
+	return hunk_low_used;
+}
+
+void Hunk_FreeToLowMark (int mark)
+{
+	if (mark < 0 || mark > hunk_low_used)
+		Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);
+	memset (hunk_base + mark, 0, hunk_low_used - mark);
+	hunk_low_used = mark;
+}
+
+int	Hunk_HighMark (void)
+{
+	if (hunk_tempactive)
+	{
+		hunk_tempactive = false;
+		Hunk_FreeToHighMark (hunk_tempmark);
+	}
+
+	return hunk_high_used;
+}
+
+void Hunk_FreeToHighMark (int mark)
+{
+	if (hunk_tempactive)
+	{
+		hunk_tempactive = false;
+		Hunk_FreeToHighMark (hunk_tempmark);
+	}
+	if (mark < 0 || mark > hunk_high_used)
+		Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
+	memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
+	hunk_high_used = mark;
+}
+
+
+/*
+===================
+Hunk_HighAllocName
+===================
+*/
+void *Hunk_HighAllocName (int size, const char *name)
+{
+	hunk_t	*h;
+
+	if (size < 0)
+		Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
+
+	if (hunk_tempactive)
+	{
+		Hunk_FreeToHighMark (hunk_tempmark);
+		hunk_tempactive = false;
+	}
+
+#ifdef PARANOID
+	Hunk_Check ();
+#endif
+
+	size = sizeof(hunk_t) + ((size+15)&~15);
+
+	if (hunk_size - hunk_low_used - hunk_high_used < size)
+	{
+		Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);
+		return NULL;
+	}
+
+	hunk_high_used += size;
+	Cache_FreeHigh (hunk_high_used);
+
+	h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
+
+	memset (h, 0, size);
+	h->size = size;
+	h->sentinal = HUNK_SENTINAL;
+	Q_strncpy (h->name, name, 8);
+
+	return (void *)(h+1);
+}
+
+
+/*
+=================
+Hunk_TempAlloc
+
+Return space from the top of the hunk
+=================
+*/
+void *Hunk_TempAlloc (int size)
+{
+	void	*buf;
+
+	size = (size+15)&~15;
+	
+	if (hunk_tempactive)
+	{
+		Hunk_FreeToHighMark (hunk_tempmark);
+		hunk_tempactive = false;
+	}
+	
+	hunk_tempmark = Hunk_HighMark ();
+
+	buf = Hunk_HighAllocName (size, "temp");
+
+	hunk_tempactive = true;
+
+	return buf;
+}
+
+/*
+===============================================================================
+
+CACHE MEMORY
+
+===============================================================================
+*/
+
+typedef struct cache_system_s
+{
+	int						size;		// including this header
+	cache_user_t			*user;
+	char					name[16];
+	struct cache_system_s	*prev, *next;
+	struct cache_system_s	*lru_prev, *lru_next;	// for LRU flushing	
+} cache_system_t;
+
+cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
+
+cache_system_t	cache_head;
+
+/*
+===========
+Cache_Move
+===========
+*/
+void Cache_Move ( cache_system_t *c)
+{
+	cache_system_t		*newc;
+
+// we are clearing up space at the bottom, so only allocate it late
+	newc = Cache_TryAlloc (c->size, true);
+	if (newc)
+	{
+//		Con_Printf ("cache_move ok\n");
+
+		Q_memcpy ( newc+1, c+1, c->size - sizeof(cache_system_t) );
+		newc->user = c->user;
+		Q_memcpy (newc->name, c->name, sizeof(newc->name));
+		Cache_Free (c->user);
+		newc->user->data = (void *)(newc+1);
+	}
+	else
+	{
+//		Con_Printf ("cache_move failed\n");
+
+		Cache_Free (c->user);		// tough luck...
+	}
+}
+
+/*
+============
+Cache_FreeLow
+
+Throw things out until the hunk can be expanded to the given point
+============
+*/
+void Cache_FreeLow (int new_low_hunk)
+{
+	cache_system_t	*c;
+	
+	while (1)
+	{
+		c = cache_head.next;
+		if (c == &cache_head)
+			return;		// nothing in cache at all
+		if ((byte *)c >= hunk_base + new_low_hunk)
+			return;		// there is space to grow the hunk
+		Cache_Move ( c );	// reclaim the space
+	}
+}
+
+/*
+============
+Cache_FreeHigh
+
+Throw things out until the hunk can be expanded to the given point
+============
+*/
+void Cache_FreeHigh (int new_high_hunk)
+{
+	cache_system_t	*c, *prev;
+	
+	prev = NULL;
+	while (1)
+	{
+		c = cache_head.prev;
+		if (c == &cache_head)
+			return;		// nothing in cache at all
+		if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)
+			return;		// there is space to grow the hunk
+		if (c == prev)
+			Cache_Free (c->user);	// didn't move out of the way
+		else
+		{
+			Cache_Move (c);	// try to move it
+			prev = c;
+		}
+	}
+}
+
+void Cache_UnlinkLRU (cache_system_t *cs)
+{
+	if (!cs->lru_next || !cs->lru_prev)
+		Sys_Error ("Cache_UnlinkLRU: NULL link");
+
+	cs->lru_next->lru_prev = cs->lru_prev;
+	cs->lru_prev->lru_next = cs->lru_next;
+	
+	cs->lru_prev = cs->lru_next = NULL;
+}
+
+void Cache_MakeLRU (cache_system_t *cs)
+{
+	if (cs->lru_next || cs->lru_prev)
+		Sys_Error ("Cache_MakeLRU: active link");
+
+	cache_head.lru_next->lru_prev = cs;
+	cs->lru_next = cache_head.lru_next;
+	cs->lru_prev = &cache_head;
+	cache_head.lru_next = cs;
+}
+
+/*
+============
+Cache_TryAlloc
+
+Looks for a free block of memory between the high and low hunk marks
+Size should already include the header and padding
+============
+*/
+cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
+{
+	cache_system_t	*cs, *newc;
+	
+// is the cache completely empty?
+
+	if (!nobottom && cache_head.prev == &cache_head)
+	{
+		if (hunk_size - hunk_high_used - hunk_low_used < size)
+			Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);
+
+		newc = (cache_system_t *) (hunk_base + hunk_low_used);
+		memset (newc, 0, sizeof(*newc));
+		newc->size = size;
+
+		cache_head.prev = cache_head.next = newc;
+		newc->prev = newc->next = &cache_head;
+		
+		Cache_MakeLRU (newc);
+		return newc;
+	}
+	
+// search from the bottom up for space
+
+	newc = (cache_system_t *) (hunk_base + hunk_low_used);
+	cs = cache_head.next;
+	
+	do
+	{
+		if (!nobottom || cs != cache_head.next)
+		{
+			if ( (byte *)cs - (byte *)newc >= size)
+			{	// found space
+				memset (newc, 0, sizeof(*newc));
+				newc->size = size;
+				
+				newc->next = cs;
+				newc->prev = cs->prev;
+				cs->prev->next = newc;
+				cs->prev = newc;
+				
+				Cache_MakeLRU (newc);
+	
+				return newc;
+			}
+		}
+
+	// continue looking		
+		newc = (cache_system_t *)((byte *)cs + cs->size);
+		cs = cs->next;
+
+	} while (cs != &cache_head);
+	
+// try to allocate one at the very end
+	if ( hunk_base + hunk_size - hunk_high_used - (byte *)newc >= size)
+	{
+		memset (newc, 0, sizeof(*newc));
+		newc->size = size;
+		
+		newc->next = &cache_head;
+		newc->prev = cache_head.prev;
+		cache_head.prev->next = newc;
+		cache_head.prev = newc;
+		
+		Cache_MakeLRU (newc);
+
+		return newc;
+	}
+	
+	return NULL;		// couldn't allocate
+}
+
+/*
+============
+Cache_Flush
+
+Throw everything out, so new data will be demand cached
+============
+*/
+void Cache_Flush (void)
+{
+	while (cache_head.next != &cache_head)
+		Cache_Free ( cache_head.next->user );	// reclaim the space
+}
+
+
+/*
+============
+Cache_Print
+
+============
+*/
+void Cache_Print (void)
+{
+	cache_system_t	*cd;
+
+	for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)
+	{
+		Con_Printf ("%8i : %s\n", cd->size, cd->name);
+	}
+}
+
+/*
+============
+Cache_Report
+
+============
+*/
+void Cache_Report (void)
+{
+	Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );
+}
+
+/*
+============
+Cache_Compact
+
+============
+*/
+void Cache_Compact (void)
+{
+}
+
+/*
+============
+Cache_Init
+
+============
+*/
+void Cache_Init (void)
+{
+	cache_head.next = cache_head.prev = &cache_head;
+	cache_head.lru_next = cache_head.lru_prev = &cache_head;
+
+	Cmd_AddCommand ("flush", Cache_Flush);
+}
+
+/*
+==============
+Cache_Free
+
+Frees the memory and removes it from the LRU list
+==============
+*/
+void Cache_Free (cache_user_t *c)
+{
+	cache_system_t	*cs;
+
+	if (!c->data)
+		Sys_Error ("Cache_Free: not allocated");
+
+	cs = ((cache_system_t *)c->data) - 1;
+
+	cs->prev->next = cs->next;
+	cs->next->prev = cs->prev;
+	cs->next = cs->prev = NULL;
+
+	c->data = NULL;
+
+	Cache_UnlinkLRU (cs);
+}
+
+
+
+/*
+==============
+Cache_Check
+==============
+*/
+void *Cache_Check (cache_user_t *c)
+{
+	cache_system_t	*cs;
+
+	if (!c->data)
+		return NULL;
+
+	cs = ((cache_system_t *)c->data) - 1;
+
+// move to head of LRU
+	Cache_UnlinkLRU (cs);
+	Cache_MakeLRU (cs);
+	
+	return c->data;
+}
+
+
+/*
+==============
+Cache_Alloc
+==============
+*/
+void *Cache_Alloc (cache_user_t *c, int size, const char *name)
+{
+	cache_system_t	*cs;
+
+	if (c->data)
+		Sys_Error ("Cache_Alloc: allready allocated");
+	
+	if (size <= 0)
+		Sys_Error ("Cache_Alloc: size %i", size);
+
+	size = (size + sizeof(cache_system_t) + 15) & ~15;
+
+// find memory for it	
+	while (1)
+	{
+		cs = Cache_TryAlloc (size, false);
+		if (cs)
+		{
+			strncpy (cs->name, name, sizeof(cs->name)-1);
+			c->data = (void *)(cs+1);
+			cs->user = c;
+			break;
+		}
+	
+	// free the least recently used cahedat
+		if (cache_head.lru_prev == &cache_head)
+			Sys_Error ("Cache_Alloc: out of memory");
+													// not enough memory at all
+		Cache_Free ( cache_head.lru_prev->user );
+	} 
+	
+	return Cache_Check (c);
+}
+
+//============================================================================
+
+
+/*
+========================
+Memory_Init
+========================
+*/
+void Memory_Init (void *buf, int size)
+{
+	int p;
+	int zonesize = DYNAMIC_SIZE;
+
+	hunk_base = (byte*) buf;
+	hunk_size = size;
+	hunk_low_used = 0;
+	hunk_high_used = 0;
+	
+	Cache_Init ();
+	p = COM_CheckParm ("-zone");
+	if (p)
+	{
+		if (p < com_argc-1)
+			zonesize = Q_atoi (com_argv[p+1]) * 1024;
+		else
+			Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
+	}
+	mainzone = (memzone_t*) Hunk_AllocName (zonesize, "zone" );
+	Z_ClearZone (mainzone, zonesize);
+}
+
diff --git a/quake/src/WinQuake/zone.h b/quake/src/WinQuake/zone.h
index b63006f..6295d6f 100644
--- a/quake/src/WinQuake/zone.h
+++ b/quake/src/WinQuake/zone.h
@@ -1,131 +1,131 @@
-/*

-Copyright (C) 1996-1997 Id Software, Inc.

-

-This program 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.

-

-This program 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 this program; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

-

-*/

-/*

- memory allocation

-

-

-H_??? The hunk manages the entire memory block given to quake.  It must be

-contiguous.  Memory can be allocated from either the low or high end in a

-stack fashion.  The only way memory is released is by resetting one of the

-pointers.

-

-Hunk allocations should be given a name, so the Hunk_Print () function

-can display usage.

-

-Hunk allocations are guaranteed to be 16 byte aligned.

-

-The video buffers are allocated high to avoid leaving a hole underneath

-server allocations when changing to a higher video mode.

-

-

-Z_??? Zone memory functions used for small, dynamic allocations like text

-strings from command input.  There is only about 48K for it, allocated at

-the very bottom of the hunk.

-

-Cache_??? Cache memory is for objects that can be dynamically loaded and

-can usefully stay persistant between levels.  The size of the cache

-fluctuates from level to level.

-

-To allocate a cachable object

-

-

-Temp_??? Temp memory is used for file loading and surface caching.  The size

-of the cache memory is adjusted so that there is a minimum of 512k remaining

-for temp memory.

-

-

------- Top of Memory -------

-

-high hunk allocations

-

-<--- high hunk reset point held by vid

-

-video buffer

-

-z buffer

-

-surface cache

-

-<--- high hunk used

-

-cachable memory

-

-<--- low hunk used

-

-client and server low hunk allocations

-

-<-- low hunk reset point held by host

-

-startup hunk allocations

-

-Zone block

-

------ Bottom of Memory -----

-

-

-

-*/

-

-void Memory_Init (void *buf, int size);

-

-void Z_Free (void *ptr);

-void *Z_Malloc (int size);			// returns 0 filled memory

-void *Z_TagMalloc (int size, int tag);

-

-void Z_DumpHeap (void);

-void Z_CheckHeap (void);

-int Z_FreeMemory (void);

-

-void *Hunk_Alloc (int size);		// returns 0 filled memory

-void *Hunk_AllocName (int size, char *name);

-

-void *Hunk_HighAllocName (int size, char *name);

-

-int	Hunk_LowMark (void);

-void Hunk_FreeToLowMark (int mark);

-

-int	Hunk_HighMark (void);

-void Hunk_FreeToHighMark (int mark);

-

-void *Hunk_TempAlloc (int size);

-

-void Hunk_Check (void);

-

-typedef struct cache_user_s

-{

-	void	*data;

-} cache_user_t;

-

-void Cache_Flush (void);

-

-void *Cache_Check (cache_user_t *c);

-// returns the cached data, and moves to the head of the LRU list

-// if present, otherwise returns NULL

-

-void Cache_Free (cache_user_t *c);

-

-void *Cache_Alloc (cache_user_t *c, int size, char *name);

-// Returns NULL if all purgable data was tossed and there still

-// wasn't enough room.

-

-void Cache_Report (void);

-

-

-

+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+/*
+ memory allocation
+
+
+H_??? The hunk manages the entire memory block given to quake.  It must be
+contiguous.  Memory can be allocated from either the low or high end in a
+stack fashion.  The only way memory is released is by resetting one of the
+pointers.
+
+Hunk allocations should be given a name, so the Hunk_Print () function
+can display usage.
+
+Hunk allocations are guaranteed to be 16 byte aligned.
+
+The video buffers are allocated high to avoid leaving a hole underneath
+server allocations when changing to a higher video mode.
+
+
+Z_??? Zone memory functions used for small, dynamic allocations like text
+strings from command input.  There is only about 48K for it, allocated at
+the very bottom of the hunk.
+
+Cache_??? Cache memory is for objects that can be dynamically loaded and
+can usefully stay persistant between levels.  The size of the cache
+fluctuates from level to level.
+
+To allocate a cachable object
+
+
+Temp_??? Temp memory is used for file loading and surface caching.  The size
+of the cache memory is adjusted so that there is a minimum of 512k remaining
+for temp memory.
+
+
+------ Top of Memory -------
+
+high hunk allocations
+
+<--- high hunk reset point held by vid
+
+video buffer
+
+z buffer
+
+surface cache
+
+<--- high hunk used
+
+cachable memory
+
+<--- low hunk used
+
+client and server low hunk allocations
+
+<-- low hunk reset point held by host
+
+startup hunk allocations
+
+Zone block
+
+----- Bottom of Memory -----
+
+
+
+*/
+
+void Memory_Init (void *buf, int size);
+
+void Z_Free (void *ptr);
+void *Z_Malloc (int size);			// returns 0 filled memory
+void *Z_TagMalloc (int size, int tag);
+
+void Z_DumpHeap (void);
+void Z_CheckHeap (void);
+int Z_FreeMemory (void);
+
+void *Hunk_Alloc (int size);		// returns 0 filled memory
+void *Hunk_AllocName (int size, const char *name);
+
+void *Hunk_HighAllocName (int size, const char *name);
+
+int	Hunk_LowMark (void);
+void Hunk_FreeToLowMark (int mark);
+
+int	Hunk_HighMark (void);
+void Hunk_FreeToHighMark (int mark);
+
+void *Hunk_TempAlloc (int size);
+
+void Hunk_Check (void);
+
+typedef struct cache_user_s
+{
+	void	*data;
+} cache_user_t;
+
+void Cache_Flush (void);
+
+void *Cache_Check (cache_user_t *c);
+// returns the cached data, and moves to the head of the LRU list
+// if present, otherwise returns NULL
+
+void Cache_Free (cache_user_t *c);
+
+void *Cache_Alloc (cache_user_t *c, int size, const char *name);
+// Returns NULL if all purgable data was tossed and there still
+// wasn't enough room.
+
+void Cache_Report (void);
+
+
+
diff --git a/res/drawable/app_quake.png b/res/drawable/app_quake.png
new file mode 100644
index 0000000..333b723
--- /dev/null
+++ b/res/drawable/app_quake.png
Binary files differ
diff --git a/res/layout/downloader.xml b/res/layout/downloader.xml
new file mode 100644
index 0000000..264a15f
--- /dev/null
+++ b/res/layout/downloader.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+      <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+          <TextView android:id="@+id/customText"
+              android:layout_width="0dip"
+              android:layout_weight="1"
+              android:layout_height="wrap_content"
+              android:padding="3dip"
+              android:textAppearance="?android:attr/textAppearanceLarge" />
+      </LinearLayout>
+      <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+          <TextView android:text="@string/download_activity_progress"
+              android:layout_width="0dip"
+              android:layout_weight="1"
+              android:layout_height="wrap_content"
+              android:padding="3dip"
+              android:gravity="right"
+              android:textAppearance="?android:attr/textAppearanceMedium" />
+          <TextView android:id="@+id/progress"
+              android:layout_width="0dip"
+              android:layout_weight="1"
+              android:layout_height="wrap_content"
+              android:padding="3dip"
+              android:textAppearance="?android:attr/textAppearanceMedium" />
+      </LinearLayout>
+
+      <LinearLayout
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content">
+          <TextView android:text="@string/download_activity_time_remaining"
+              android:layout_width="0dip"
+              android:layout_weight="1"
+              android:layout_height="wrap_content"
+              android:padding="3dip"
+              android:gravity="right"
+              android:textAppearance="?android:attr/textAppearanceMedium" />
+          <TextView android:id="@+id/time_remaining"
+              android:layout_width="0dip"
+              android:layout_weight="1"
+              android:layout_height="wrap_content"
+              android:padding="3dip"
+              android:textAppearance="?android:attr/textAppearanceMedium" />
+      </LinearLayout>
+
+  <Button android:id="@+id/cancel"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:layout_marginTop="5dip"
+    android:text="@string/download_activity_cancel" />
+</LinearLayout>
diff --git a/res/layout/downloader_title.xml b/res/layout/downloader_title.xml
new file mode 100644
index 0000000..1acdbed
--- /dev/null
+++ b/res/layout/downloader_title.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+    * Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    *      http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/screen"
+    android:layout_width="fill_parent"
+    android:layout_height="?android:attr/windowTitleSize"
+    android:orientation="horizontal">
+
+    <TextView android:id="@+id/title_text"
+        android:gravity="center_vertical"
+        android:layout_width="0dip"
+        android:layout_height="fill_parent"
+        android:paddingLeft="5dip"
+        style="?android:attr/windowTitleStyle"
+        android:singleLine="true"
+        android:layout_weight="1"
+        android:ellipsize="end" />
+
+    <LinearLayout android:id="@+id/loading_indicator"
+        android:orientation="horizontal"
+        android:gravity="center_vertical"
+        android:layout_height="fill_parent"
+        android:layout_width="wrap_content">
+
+        <TextView android:text="@string/download_activity_title"
+            android:gravity="center_vertical"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:paddingRight="5dip"
+            style="?android:attr/windowTitleStyle" />
+
+        <ProgressBar android:id="@android:id/progress"
+            style="?android:attr/progressBarStyleSmallTitle"
+            android:layout_gravity="center_vertical"
+            android:paddingRight="5dip"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..17fb7e2
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/Quake/res/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!-- This file contains resource definitions for displayed strings, allowing
+     them to be changed based on the locale and options. -->
+
+<resources>
+    <!-- Simple strings. -->
+    <string name="quake_activity">Quake</string>
+    <string name="quake_customDownloadText">Please wait while the Quake data files are copied to your SD card.</string>
+    <string name="download_activity_title">Downloading</string>
+    <string name="download_activity_cancel">Cancel Download</string>
+    <string name="download_activity_progress">Progress:</string>
+    <string name="download_activity_time_remaining">Time Remaining:</string>
+    <string name="download_activity_time_remaining_unknown">unknown</string>
+    <string name="download_activity_time_remaining_minutes">minutes</string>
+    <string name="download_activity_time_remaining_seconds">seconds</string>
+    <string name="download_activity_time_remaining_hours">hours</string>
+    <string name="download_activity_time_remaining_days">days</string>
+    <string name="download_activity_download_stopped">Download stopped</string>
+    <string name="download_activity_retry">Retry</string>
+    <string name="download_activity_quit">Quit</string>
+
+</resources>
+
diff --git a/setupdevice.sh b/setupdevice.sh
new file mode 100755
index 0000000..b808595
--- /dev/null
+++ b/setupdevice.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Copy Quake's data files from perforce to the Android device's data directory.
+# Based on emulator.sh
+#
+
+# This funcion is copied from envsetup.sh
+
+function gettop
+{
+    TOPFILE=config/envsetup.make
+    if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
+        echo $TOP
+    else
+        if [ -f $TOPFILE ] ; then
+            echo $PWD
+        else
+            HERE=$PWD
+            T=
+            while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+                cd ..
+                T=$PWD
+            done
+            cd $HERE
+            if [ -f "$T/$TOPFILE" ]; then
+                echo $T
+            fi
+        fi
+    fi
+}
+
+T=$(gettop)
+if [ -z "$T" ] ; then
+    echo "please run your envsetup.sh script"
+    exit 1
+fi
+
+echo "top found at $T"
+
+
+echo "Creating Quake directories on the device"
+
+adb shell mkdir /data
+adb shell mkdir /data/quake
+adb shell mkdir /data/quake/id1
+
+echo "Copying Quake data files to the device. (This could take several minutes)"
+adb push $T/apps/Quake/quake/app/id1 /data/quake/id1
+echo "Done."
\ No newline at end of file
diff --git a/setupdevicesdcard.sh b/setupdevicesdcard.sh
new file mode 100755
index 0000000..f6aa2a9
--- /dev/null
+++ b/setupdevicesdcard.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Copy Quake's data files from perforce to the Android device's sd card.
+# Based on emulator.sh
+#
+
+# We need some internal functions defined in envsetup.sh, so start
+# by finding this file and sourcing it before anything else
+#
+function gettop
+{
+    TOPFILE=config/envsetup.make
+    if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
+        echo $TOP
+    else
+        if [ -f $TOPFILE ] ; then
+            echo $PWD
+        else
+            HERE=$PWD
+            T=
+            while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
+                cd ..
+                T=$PWD
+            done
+            cd $HERE
+            if [ -f "$T/$TOPFILE" ]; then
+                echo $T
+            fi
+        fi
+    fi
+}
+
+T=$(gettop)
+if [ -z "$T" ] ; then
+    echo "please run your envsetup.sh script"
+    exit 1
+fi
+
+echo "top found at $T"
+
+echo "Creating Quake directories on the device's sdcard"
+
+adb shell mkdir /sdcard
+adb shell mkdir /sdcard/data
+adb shell mkdir /sdcard/data/quake
+adb shell mkdir /sdcard/data/quake/id1
+
+echo "Copying Quake data files to the device. (This could take several minutes)"
+adb push $T/apps/Quake/quake/app/id1 /sdcard/data/quake/id1
+echo "Done."
\ No newline at end of file
diff --git a/setupsim.sh b/setupsim.sh
new file mode 100755
index 0000000..e873fc6
--- /dev/null
+++ b/setupsim.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# Copy Quake's data files from perforce to the Android simulator's data directory.
+
+
+# create and populate data quake directory.
+echo "Creating a /data directory to hold the simulator data files"
+mkdir -m 755 -p /data/quake/id1
+echo "Copying Quake data files to simulator data directory..."
+cp -f quake/app/id1/* /data/quake/id1
+
+
diff --git a/src/com/android/quake/DownloaderActivity.java b/src/com/android/quake/DownloaderActivity.java
new file mode 100644
index 0000000..bec258c
--- /dev/null
+++ b/src/com/android/quake/DownloaderActivity.java
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quake;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.channels.FileLock;
+
+import android.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.http.AndroidHttpClient;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Xml;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+public class DownloaderActivity extends Activity {
+
+    /**
+     * Checks if data has been downloaded. If so, returns true. If not,
+     * starts an activity to download the data and returns false. If this
+     * function returns false the caller should immediately return from its
+     * onCreate method. The calling activity will later be restarted
+     * (using a copy of its original intent) once the data download completes.
+     * @param activity The calling activity.
+     * @param customText A text string that is displayed in the downloader UI.
+     * @param fileConfigUrl The URL of the download configuration URL.
+     * @param configVersion The version of the configuration file.
+     * @param dataPath The directory on the device where we want to store the
+     * data.
+     * @param userAgent The user agent string to use when fetching URLs.
+     * @return true if the data has already been downloaded successfully, or
+     * false if the data needs to be downloaded.
+     */
+    public static boolean ensureDownloaded(Activity activity,
+            String customText, String fileConfigUrl,
+            String configVersion, String dataPath,
+            String userAgent) {
+        File dest = new File(dataPath);
+        if (dest.exists()) {
+            // Check version
+            if (versionMatches(dest, configVersion)) {
+                Log.i(LOG_TAG, "Versions match, no need to download.");
+                return true;
+            }
+        }
+        Intent intent = PreconditionActivityHelper.createPreconditionIntent(
+                activity, DownloaderActivity.class);
+        intent.putExtra(EXTRA_CUSTOM_TEXT, customText);
+        intent.putExtra(EXTRA_FILE_CONFIG_URL, fileConfigUrl);
+        intent.putExtra(EXTRA_CONFIG_VERSION, configVersion);
+        intent.putExtra(EXTRA_DATA_PATH, dataPath);
+        intent.putExtra(EXTRA_USER_AGENT, userAgent);
+        PreconditionActivityHelper.startPreconditionActivityAndFinish(
+                activity, intent);
+        return false;
+    }
+
+    /**
+     * Delete a directory and all its descendants.
+     * @param directory The directory to delete
+     * @return true if the directory was deleted successfully.
+     */
+    public static boolean deleteData(String directory) {
+        return deleteTree(new File(directory), true);
+    }
+
+    private static boolean deleteTree(File base, boolean deleteBase) {
+        boolean result = true;
+        if (base.isDirectory()) {
+            for (File child : base.listFiles()) {
+                result &= deleteTree(child, true);
+            }
+        }
+        if (deleteBase) {
+            result &= base.delete();
+        }
+        return result;
+    }
+
+    private static boolean versionMatches(File dest, String expectedVersion) {
+        Config config = getLocalConfig(dest, LOCAL_CONFIG_FILE);
+        if (config != null) {
+            return config.version.equals(expectedVersion);
+        }
+        return false;
+    }
+
+    private static Config getLocalConfig(File destPath, String configFilename) {
+        File configPath = new File(destPath, configFilename);
+        FileInputStream is;
+        try {
+            is = new FileInputStream(configPath);
+        } catch (FileNotFoundException e) {
+            return null;
+        }
+        try {
+            Config config = ConfigHandler.parse(is);
+            return config;
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Unable to read local config file", e);
+            return null;
+        } finally {
+            quietClose(is);
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
+        setContentView(R.layout.downloader);
+        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
+                R.layout.downloader_title);
+        ((TextView) findViewById(R.id.customText)).setText(
+                intent.getStringExtra(EXTRA_CUSTOM_TEXT));
+        mProgress = (TextView) findViewById(R.id.progress);
+        mTimeRemaining = (TextView) findViewById(R.id.time_remaining);
+        Button button = (Button) findViewById(R.id.cancel);
+        button.setOnClickListener(new Button.OnClickListener() {
+            public void onClick(View v) {
+                if (mDownloadThread != null) {
+                    mSuppressErrorMessages = true;
+                    mDownloadThread.interrupt();
+                }
+            }
+        });
+        startDownloadThread();
+    }
+
+    private void startDownloadThread() {
+        mSuppressErrorMessages = false;
+        mProgress.setText("");
+        mTimeRemaining.setText("");
+        mDownloadThread = new Thread(new Downloader(), "Downloader");
+        mDownloadThread.setPriority(Thread.NORM_PRIORITY - 1);
+        mDownloadThread.start();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mSuppressErrorMessages = true;
+        mDownloadThread.interrupt();
+        try {
+            mDownloadThread.join();
+        } catch (InterruptedException e) {
+            // Don't care.
+        }
+    }
+
+    private void onDownloadSucceeded() {
+        Log.i(LOG_TAG, "Download succeeded");
+        PreconditionActivityHelper.startOriginalActivityAndFinish(this);
+    }
+
+    private void onDownloadFailed(String reason) {
+        Log.e(LOG_TAG, "Download stopped: " + reason);
+        String shortReason;
+        int index = reason.indexOf('\n');
+        if (index >= 0) {
+            shortReason = reason.substring(0, index);
+        } else {
+            shortReason = reason;
+        }
+        AlertDialog alert = new Builder(this).create();
+        alert.setTitle(R.string.download_activity_download_stopped);
+
+        if (!mSuppressErrorMessages) {
+            alert.setMessage(shortReason);
+        }
+
+        alert.setButton(getString(R.string.download_activity_retry),
+                new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int which) {
+                startDownloadThread();
+            }
+
+        });
+        alert.setButton2(getString(R.string.download_activity_quit),
+                new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int which) {
+                finish();
+            }
+
+        });
+        try {
+            alert.show();
+        } catch (WindowManager.BadTokenException e) {
+            // Happens when the Back button is used to exit the activity.
+            // ignore.
+        }
+    }
+
+    private void onReportProgress(int progress) {
+        mProgress.setText(mPercentFormat.format(progress / 10000.0));
+        long now = SystemClock.elapsedRealtime();
+        if (mStartTime == 0) {
+            mStartTime = now;
+        }
+        long delta = now - mStartTime;
+        String timeRemaining = getString(R.string.download_activity_time_remaining_unknown);
+        if ((delta > 3 * MS_PER_SECOND) && (progress > 100)) {
+            long totalTime = 10000 * delta / progress;
+            long timeLeft = Math.max(0L, totalTime - delta);
+            if (timeLeft > MS_PER_DAY) {
+                timeRemaining = Long.toString(
+                    (timeLeft + MS_PER_DAY - 1) / MS_PER_DAY)
+                    + " "
+                    + getString(R.string.download_activity_time_remaining_days);
+            } else if (timeLeft > MS_PER_HOUR) {
+                timeRemaining = Long.toString(
+                        (timeLeft + MS_PER_HOUR - 1) / MS_PER_HOUR)
+                        + " "
+                        + getString(R.string.download_activity_time_remaining_hours);
+            } else if (timeLeft > MS_PER_MINUTE) {
+                timeRemaining = Long.toString(
+                        (timeLeft + MS_PER_MINUTE - 1) / MS_PER_MINUTE)
+                        + " "
+                        + getString(R.string.download_activity_time_remaining_minutes);
+            } else {
+                timeRemaining = Long.toString(
+                        (timeLeft + MS_PER_SECOND - 1) / MS_PER_SECOND)
+                        + " "
+                        + getString(R.string.download_activity_time_remaining_seconds);
+            }
+        }
+        mTimeRemaining.setText(timeRemaining);
+    }
+
+    private static void quietClose(InputStream is) {
+        try {
+            if (is != null) {
+                is.close();
+            }
+        } catch (IOException e) {
+            // Don't care.
+        }
+    }
+
+    private static void quietClose(OutputStream os) {
+        try {
+            if (os != null) {
+                os.close();
+            }
+        } catch (IOException e) {
+            // Don't care.
+        }
+    }
+
+    private static class Config {
+        long getSize() {
+            long result = 0;
+            for(File file : mFiles) {
+                result += file.getSize();
+            }
+            return result;
+        }
+        static class File {
+            public File(String src, String dest, String md5, long size) {
+                if (src != null) {
+                    this.mParts.add(new Part(src, md5, size));
+                }
+                this.dest = dest;
+            }
+            static class Part {
+                Part(String src, String md5, long size) {
+                    this.src = src;
+                    this.md5 = md5;
+                    this.size = size;
+                }
+                String src;
+                String md5;
+                long size;
+            }
+            ArrayList<Part> mParts = new ArrayList<Part>();
+            String dest;
+            long getSize() {
+                long result = 0;
+                for(Part part : mParts) {
+                    if (part.size > 0) {
+                        result += part.size;
+                    }
+                }
+                return result;
+            }
+        }
+        String version;
+        ArrayList<File> mFiles = new ArrayList<File>();
+    }
+
+    /**
+     * <config version="">
+     *   <file src="http:..." dest ="b.x" />
+     *   <file dest="b.x">
+     *     <part src="http:..." />
+     *     ...
+     *   ...
+     * </config>
+     *
+     */
+    private static class ConfigHandler extends DefaultHandler {
+
+        public static Config parse(InputStream is) throws SAXException,
+            UnsupportedEncodingException, IOException {
+            ConfigHandler handler = new ConfigHandler();
+            Xml.parse(is, Xml.findEncodingByName("UTF-8"), handler);
+            return handler.mConfig;
+        }
+
+        private ConfigHandler() {
+            mConfig = new Config();
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName,
+                Attributes attributes) throws SAXException {
+            if (localName.equals("config")) {
+                mConfig.version = getRequiredString(attributes, "version");
+            } else if (localName.equals("file")) {
+                String src = attributes.getValue("", "src");
+                String dest = getRequiredString(attributes, "dest");
+                String md5 = attributes.getValue("", "md5");
+                long size = getLong(attributes, "size", -1);
+                mConfig.mFiles.add(new Config.File(src, dest, md5, size));
+            } else if (localName.equals("part")) {
+                String src = getRequiredString(attributes, "src");
+                String md5 = attributes.getValue("", "md5");
+                long size = getLong(attributes, "size", -1);
+                int length = mConfig.mFiles.size();
+                if (length > 0) {
+                    mConfig.mFiles.get(length-1).mParts.add(
+                            new Config.File.Part(src, md5, size));
+                }
+            }
+        }
+
+        private static String getRequiredString(Attributes attributes,
+                String localName) throws SAXException {
+            String result = attributes.getValue("", localName);
+            if (result == null) {
+                throw new SAXException("Expected attribute " + localName);
+            }
+            return result;
+        }
+
+        private static long getLong(Attributes attributes, String localName,
+                long defaultValue) {
+            String value = attributes.getValue("", localName);
+            if (value == null) {
+                return defaultValue;
+            } else {
+                return Long.parseLong(value);
+            }
+        }
+
+        public Config mConfig;
+    }
+
+    private class DownloaderException extends Exception {
+        public DownloaderException(String reason) {
+            super(reason);
+        }
+    }
+
+    private class Downloader implements Runnable {
+        public void run() {
+            Intent intent = getIntent();
+            mFileConfigUrl = intent.getStringExtra(EXTRA_FILE_CONFIG_URL);
+            mConfigVersion = intent.getStringExtra(EXTRA_CONFIG_VERSION);
+            mDataPath = intent.getStringExtra(EXTRA_DATA_PATH);
+            mUserAgent = intent.getStringExtra(EXTRA_USER_AGENT);
+
+            mDataDir = new File(mDataPath);
+
+            try {
+                // Download files.
+                mHttpClient = AndroidHttpClient.newInstance(mUserAgent);
+                try {
+                    Config config = getConfig();
+                    filter(config);
+                    persistantDownload(config);
+                    verify(config);
+                    cleanup();
+                    reportSuccess();
+                } finally {
+                    mHttpClient.close();
+                }
+            } catch (Exception e) {
+                reportFailure(e.toString() + "\n" + Log.getStackTraceString(e));
+            }
+        }
+
+        private void persistantDownload(Config config)
+        throws ClientProtocolException, DownloaderException, IOException {
+            while(true) {
+                try {
+                    download(config);
+                    break;
+                } catch(java.net.SocketException e) {
+                    if (mSuppressErrorMessages) {
+                        throw e;
+                    }
+                } catch(java.net.SocketTimeoutException e) {
+                    if (mSuppressErrorMessages) {
+                        throw e;
+                    }
+                }
+                Log.i(LOG_TAG, "Network connectivity issue, retrying.");
+            }
+        }
+
+        private void filter(Config config)
+        throws IOException, DownloaderException {
+            File filteredFile = new File(mDataDir, LOCAL_FILTERED_FILE);
+            if (filteredFile.exists()) {
+                return;
+            }
+
+            File localConfigFile = new File(mDataDir, LOCAL_CONFIG_FILE_TEMP);
+            HashSet<String> keepSet = new HashSet<String>();
+            keepSet.add(localConfigFile.getCanonicalPath());
+
+            HashMap<String, Config.File> fileMap =
+                new HashMap<String, Config.File>();
+            for(Config.File file : config.mFiles) {
+                String canonicalPath =
+                    new File(mDataDir, file.dest).getCanonicalPath();
+                fileMap.put(canonicalPath, file);
+            }
+            recursiveFilter(mDataDir, fileMap, keepSet, false);
+            touch(filteredFile);
+        }
+
+        private void touch(File file) throws FileNotFoundException {
+            FileOutputStream os = new FileOutputStream(file);
+            quietClose(os);
+        }
+
+        private boolean recursiveFilter(File base,
+                HashMap<String, Config.File> fileMap,
+                HashSet<String> keepSet, boolean filterBase)
+        throws IOException, DownloaderException {
+            boolean result = true;
+            if (base.isDirectory()) {
+                for (File child : base.listFiles()) {
+                    result &= recursiveFilter(child, fileMap, keepSet, true);
+                }
+            }
+            if (filterBase) {
+                if (base.isDirectory()) {
+                    if (base.listFiles().length == 0) {
+                        result &= base.delete();
+                    }
+                } else {
+                    if (!shouldKeepFile(base, fileMap, keepSet)) {
+                        result &= base.delete();
+                    }
+                }
+            }
+            return result;
+        }
+
+        private boolean shouldKeepFile(File file,
+                HashMap<String, Config.File> fileMap,
+                HashSet<String> keepSet)
+        throws IOException, DownloaderException {
+            String canonicalPath = file.getCanonicalPath();
+            if (keepSet.contains(canonicalPath)) {
+                return true;
+            }
+            Config.File configFile = fileMap.get(canonicalPath);
+            if (configFile == null) {
+                return false;
+            }
+            return verifyFile(configFile, false);
+        }
+
+        private void reportSuccess() {
+            mHandler.sendMessage(
+                    Message.obtain(mHandler, MSG_DOWNLOAD_SUCCEEDED));
+        }
+
+        private void reportFailure(String reason) {
+            mHandler.sendMessage(
+                    Message.obtain(mHandler, MSG_DOWNLOAD_FAILED, reason));
+        }
+
+        private void reportProgress(int progress) {
+            mHandler.sendMessage(
+                    Message.obtain(mHandler, MSG_REPORT_PROGRESS, progress, 0));
+        }
+
+        private Config getConfig() throws DownloaderException,
+            ClientProtocolException, IOException, SAXException {
+            Config config = null;
+            if (mDataDir.exists()) {
+                config = getLocalConfig(mDataDir, LOCAL_CONFIG_FILE_TEMP);
+                if ((config == null)
+                        || !mConfigVersion.equals(config.version)) {
+                    if (config == null) {
+                        Log.i(LOG_TAG, "Couldn't find local config.");
+                    } else {
+                        Log.i(LOG_TAG, "Local version out of sync. Wanted " +
+                                mConfigVersion + " but have " + config.version);
+                    }
+                    config = null;
+                }
+            } else {
+                Log.i(LOG_TAG, "Creating directory " + mDataPath);
+                mDataDir.mkdirs();
+                mDataDir.mkdir();
+                if (!mDataDir.exists()) {
+                    throw new DownloaderException(
+                            "Could not create the directory " + mDataPath);
+                }
+            }
+            if (config == null) {
+                File localConfig = download(mFileConfigUrl,
+                        LOCAL_CONFIG_FILE_TEMP);
+                InputStream is = new FileInputStream(localConfig);
+                try {
+                    config = ConfigHandler.parse(is);
+                } finally {
+                    quietClose(is);
+                }
+                if (! config.version.equals(mConfigVersion)) {
+                    throw new DownloaderException(
+                            "Configuration file version mismatch. Expected " +
+                            mConfigVersion + " received " +
+                            config.version);
+                }
+            }
+            return config;
+        }
+
+        private void noisyDelete(File file) throws IOException {
+            if (! file.delete() ) {
+                throw new IOException("could not delete " + file);
+            }
+        }
+
+        private void download(Config config) throws DownloaderException,
+            ClientProtocolException, IOException {
+            mDownloadedSize = 0;
+            getSizes(config);
+            Log.i(LOG_TAG, "Total bytes to download: "
+                    + mTotalExpectedSize);
+            for(Config.File file : config.mFiles) {
+                downloadFile(file);
+            }
+        }
+
+        private void downloadFile(Config.File file) throws DownloaderException,
+                FileNotFoundException, IOException, ClientProtocolException {
+            boolean append = false;
+            File dest = new File(mDataDir, file.dest);
+            long bytesToSkip = 0;
+            if (dest.exists() && dest.isFile()) {
+                append = true;
+                bytesToSkip = dest.length();
+                mDownloadedSize += bytesToSkip;
+            }
+            FileOutputStream os = null;
+            long offsetOfCurrentPart = 0;
+            try {
+                for(Config.File.Part part : file.mParts) {
+                    // The part.size==0 check below allows us to download
+                    // zero-length files.
+                    if ((part.size > bytesToSkip) || (part.size == 0)) {
+                        MessageDigest digest = null;
+                        if (part.md5 != null) {
+                            digest = createDigest();
+                            if (bytesToSkip > 0) {
+                                FileInputStream is = openInput(file.dest);
+                                try {
+                                    is.skip(offsetOfCurrentPart);
+                                    readIntoDigest(is, bytesToSkip, digest);
+                                } finally {
+                                    quietClose(is);
+                                }
+                            }
+                        }
+                        if (os == null) {
+                            os = openOutput(file.dest, append);
+                        }
+                        downloadPart(part.src, os, bytesToSkip,
+                                part.size, digest);
+                        if (digest != null) {
+                            String hash = getHash(digest);
+                            if (!hash.equalsIgnoreCase(part.md5)) {
+                                Log.e(LOG_TAG, "web MD5 checksums don't match. "
+                                        + part.src + "\nExpected "
+                                        + part.md5 + "\n     got " + hash);
+                                quietClose(os);
+                                dest.delete();
+                                throw new DownloaderException(
+                                      "Received bad data from web server");
+                            } else {
+                               Log.i(LOG_TAG, "web MD5 checksum matches.");
+                            }
+                        }
+                    }
+                    bytesToSkip -= Math.min(bytesToSkip, part.size);
+                    offsetOfCurrentPart += part.size;
+                }
+            } finally {
+                quietClose(os);
+            }
+        }
+
+        private void cleanup() throws IOException {
+            File filtered = new File(mDataDir, LOCAL_FILTERED_FILE);
+            noisyDelete(filtered);
+            File tempConfig = new File(mDataDir, LOCAL_CONFIG_FILE_TEMP);
+            File realConfig = new File(mDataDir, LOCAL_CONFIG_FILE);
+            tempConfig.renameTo(realConfig);
+        }
+
+        private void verify(Config config) throws DownloaderException,
+        ClientProtocolException, IOException {
+            Log.i(LOG_TAG, "Verifying...");
+            String failFiles = null;
+            for(Config.File file : config.mFiles) {
+                if (! verifyFile(file, true) ) {
+                    if (failFiles == null) {
+                        failFiles = file.dest;
+                    } else {
+                        failFiles += " " + file.dest;
+                    }
+                }
+            }
+            if (failFiles != null) {
+                throw new DownloaderException(
+                        "Possible bad SD-Card. MD5 sum incorrect for file(s) "
+                        + failFiles);
+            }
+        }
+
+        private boolean verifyFile(Config.File file, boolean deleteInvalid)
+                throws FileNotFoundException, DownloaderException, IOException {
+            Log.i(LOG_TAG, "verifying " + file.dest);
+            File dest = new File(mDataDir, file.dest);
+            if (! dest.exists()) {
+                Log.e(LOG_TAG, "File does not exist: " + dest.toString());
+                return false;
+            }
+            long fileSize = file.getSize();
+            long destLength = dest.length();
+            if (fileSize != destLength) {
+                Log.e(LOG_TAG, "Length doesn't match. Expected " + fileSize
+                        + " got " + destLength);
+                if (deleteInvalid) {
+                    dest.delete();
+                    return false;
+                }
+            }
+            FileInputStream is = new FileInputStream(dest);
+            try {
+                for(Config.File.Part part : file.mParts) {
+                    if (part.md5 == null) {
+                        continue;
+                    }
+                    MessageDigest digest = createDigest();
+                    readIntoDigest(is, part.size, digest);
+                    String hash = getHash(digest);
+                    if (!hash.equalsIgnoreCase(part.md5)) {
+                        Log.e(LOG_TAG, "MD5 checksums don't match. " +
+                                part.src + " Expected "
+                                + part.md5 + " got " + hash);
+                        if (deleteInvalid) {
+                            quietClose(is);
+                            dest.delete();
+                        }
+                        return false;
+                    }
+                }
+            } finally {
+                quietClose(is);
+            }
+            return true;
+        }
+
+        private void readIntoDigest(FileInputStream is, long bytesToRead,
+                MessageDigest digest) throws IOException {
+            while(bytesToRead > 0) {
+                int chunkSize = (int) Math.min(mFileIOBuffer.length,
+                        bytesToRead);
+                int bytesRead = is.read(mFileIOBuffer, 0, chunkSize);
+                if (bytesRead < 0) {
+                    break;
+                }
+                updateDigest(digest, bytesRead);
+                bytesToRead -= bytesRead;
+            }
+        }
+
+        private MessageDigest createDigest() throws DownloaderException {
+            MessageDigest digest;
+            try {
+                digest = MessageDigest.getInstance("MD5");
+            } catch (NoSuchAlgorithmException e) {
+                throw new DownloaderException("Couldn't create MD5 digest");
+            }
+            return digest;
+        }
+
+        private void updateDigest(MessageDigest digest, int bytesRead) {
+            if (bytesRead == mFileIOBuffer.length) {
+                digest.update(mFileIOBuffer);
+            } else {
+                // Work around an awkward API: Create a
+                // new buffer with just the valid bytes
+                byte[] temp = new byte[bytesRead];
+                System.arraycopy(mFileIOBuffer, 0,
+                        temp, 0, bytesRead);
+                digest.update(temp);
+            }
+        }
+
+        private String getHash(MessageDigest digest) {
+            StringBuilder builder = new StringBuilder();
+            for(byte b : digest.digest()) {
+                builder.append(Integer.toHexString((b >> 4) & 0xf));
+                builder.append(Integer.toHexString(b & 0xf));
+            }
+            return builder.toString();
+        }
+
+
+        /**
+         * Ensure we have sizes for all the items.
+         * @param config
+         * @throws ClientProtocolException
+         * @throws IOException
+         * @throws DownloaderException
+         */
+        private void getSizes(Config config)
+            throws ClientProtocolException, IOException, DownloaderException {
+            for (Config.File file : config.mFiles) {
+                for(Config.File.Part part : file.mParts) {
+                    if (part.size < 0) {
+                        part.size = getSize(part.src);
+                    }
+                }
+            }
+            mTotalExpectedSize = config.getSize();
+        }
+
+        private long getSize(String url) throws ClientProtocolException,
+            IOException {
+            url = normalizeUrl(url);
+            Log.i(LOG_TAG, "Head " + url);
+            HttpHead httpGet = new HttpHead(url);
+            HttpResponse response = mHttpClient.execute(httpGet);
+            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+                throw new IOException("Unexpected Http status code "
+                    + response.getStatusLine().getStatusCode());
+            }
+            Header[] clHeaders = response.getHeaders("Content-Length");
+            if (clHeaders.length > 0) {
+                Header header = clHeaders[0];
+                return Long.parseLong(header.getValue());
+            }
+            return -1;
+        }
+
+        private String normalizeUrl(String url) throws MalformedURLException {
+            return (new URL(new URL(mFileConfigUrl), url)).toString();
+        }
+
+        private InputStream get(String url, long startOffset,
+                long expectedLength)
+            throws ClientProtocolException, IOException {
+            url = normalizeUrl(url);
+            Log.i(LOG_TAG, "Get " + url);
+
+            mHttpGet = new HttpGet(url);
+            int expectedStatusCode = HttpStatus.SC_OK;
+            if (startOffset > 0) {
+                String range = "bytes=" + startOffset + "-";
+                if (expectedLength >= 0) {
+                    range += expectedLength-1;
+                }
+                Log.i(LOG_TAG, "requesting byte range " + range);
+                mHttpGet.addHeader("Range", range);
+                expectedStatusCode = HttpStatus.SC_PARTIAL_CONTENT;
+            }
+            HttpResponse response = mHttpClient.execute(mHttpGet);
+            long bytesToSkip = 0;
+            int statusCode = response.getStatusLine().getStatusCode();
+            if (statusCode != expectedStatusCode) {
+                if ((statusCode == HttpStatus.SC_OK)
+                        && (expectedStatusCode
+                                == HttpStatus.SC_PARTIAL_CONTENT)) {
+                    Log.i(LOG_TAG, "Byte range request ignored");
+                    bytesToSkip = startOffset;
+                } else {
+                    throw new IOException("Unexpected Http status code "
+                            + statusCode + " expected "
+                            + expectedStatusCode);
+                }
+            }
+            HttpEntity entity = response.getEntity();
+            InputStream is = entity.getContent();
+            if (bytesToSkip > 0) {
+                is.skip(bytesToSkip);
+            }
+            return is;
+        }
+
+        private File download(String src, String dest)
+            throws DownloaderException, ClientProtocolException, IOException {
+            File destFile = new File(mDataDir, dest);
+            FileOutputStream os = openOutput(dest, false);
+            try {
+                downloadPart(src, os, 0, -1, null);
+            } finally {
+                os.close();
+            }
+            return destFile;
+        }
+
+        private void downloadPart(String src, FileOutputStream os,
+                long startOffset, long expectedLength, MessageDigest digest)
+            throws ClientProtocolException, IOException, DownloaderException {
+            boolean lengthIsKnown = expectedLength >= 0;
+            if (startOffset < 0) {
+                throw new IllegalArgumentException("Negative startOffset:"
+                        + startOffset);
+            }
+            if (lengthIsKnown && (startOffset > expectedLength)) {
+                throw new IllegalArgumentException(
+                        "startOffset > expectedLength" + startOffset + " "
+                        + expectedLength);
+            }
+            InputStream is = get(src, startOffset, expectedLength);
+            try {
+                long bytesRead = downloadStream(is, os, digest);
+                if (lengthIsKnown) {
+                    long expectedBytesRead = expectedLength - startOffset;
+                    if (expectedBytesRead != bytesRead) {
+                        Log.e(LOG_TAG, "Bad file transfer from server: " + src
+                                + " Expected " + expectedBytesRead
+                                + " Received " + bytesRead);
+                        throw new DownloaderException(
+                                "Incorrect number of bytes received from server");
+                    }
+                }
+            } finally {
+                is.close();
+                mHttpGet = null;
+            }
+        }
+
+        private FileOutputStream openOutput(String dest, boolean append)
+            throws FileNotFoundException, DownloaderException {
+            File destFile = new File(mDataDir, dest);
+            File parent = destFile.getParentFile();
+            if (! parent.exists()) {
+                parent.mkdirs();
+            }
+            if (! parent.exists()) {
+                throw new DownloaderException("Could not create directory "
+                        + parent.toString());
+            }
+            FileOutputStream os = new FileOutputStream(destFile, append);
+            return os;
+        }
+
+        private FileInputStream openInput(String src)
+            throws FileNotFoundException, DownloaderException {
+            File srcFile = new File(mDataDir, src);
+            File parent = srcFile.getParentFile();
+            if (! parent.exists()) {
+                parent.mkdirs();
+            }
+            if (! parent.exists()) {
+                throw new DownloaderException("Could not create directory "
+                        + parent.toString());
+            }
+            return new FileInputStream(srcFile);
+        }
+
+        private long downloadStream(InputStream is, FileOutputStream os,
+                MessageDigest digest)
+                throws DownloaderException, IOException {
+            long totalBytesRead = 0;
+            while(true){
+                if (Thread.interrupted()) {
+                    Log.i(LOG_TAG, "downloader thread interrupted.");
+                    mHttpGet.abort();
+                    throw new DownloaderException("Thread interrupted");
+                }
+                int bytesRead = is.read(mFileIOBuffer);
+                if (bytesRead < 0) {
+                    break;
+                }
+                if (digest != null) {
+                    updateDigest(digest, bytesRead);
+                }
+                totalBytesRead += bytesRead;
+                os.write(mFileIOBuffer, 0, bytesRead);
+                mDownloadedSize += bytesRead;
+                int progress = (int) (Math.min(mTotalExpectedSize,
+                        mDownloadedSize * 10000 /
+                        Math.max(1, mTotalExpectedSize)));
+                if (progress != mReportedProgress) {
+                    mReportedProgress = progress;
+                    reportProgress(progress);
+                }
+            }
+            return totalBytesRead;
+        }
+
+        private AndroidHttpClient mHttpClient;
+        private HttpGet mHttpGet;
+        private String mFileConfigUrl;
+        private String mConfigVersion;
+        private String mDataPath;
+        private File mDataDir;
+        private String mUserAgent;
+        private long mTotalExpectedSize;
+        private long mDownloadedSize;
+        private int mReportedProgress;
+        private final static int CHUNK_SIZE = 32 * 1024;
+        byte[] mFileIOBuffer = new byte[CHUNK_SIZE];
+    }
+
+    private final static String LOG_TAG = "Downloader";
+    private TextView mProgress;
+    private TextView mTimeRemaining;
+    private final DecimalFormat mPercentFormat = new DecimalFormat("0.00 %");
+    private long mStartTime;
+    private Thread mDownloadThread;
+    private boolean mSuppressErrorMessages;
+
+    private final static long MS_PER_SECOND = 1000;
+    private final static long MS_PER_MINUTE = 60 * 1000;
+    private final static long MS_PER_HOUR = 60 * 60 * 1000;
+    private final static long MS_PER_DAY = 24 * 60 * 60 * 1000;
+
+    private final static String LOCAL_CONFIG_FILE = ".downloadConfig";
+    private final static String LOCAL_CONFIG_FILE_TEMP = ".downloadConfig_temp";
+    private final static String LOCAL_FILTERED_FILE = ".downloadConfig_filtered";
+    private final static String EXTRA_CUSTOM_TEXT = "DownloaderActivity_custom_text";
+    private final static String EXTRA_FILE_CONFIG_URL = "DownloaderActivity_config_url";
+    private final static String EXTRA_CONFIG_VERSION = "DownloaderActivity_config_version";
+    private final static String EXTRA_DATA_PATH = "DownloaderActivity_data_path";
+    private final static String EXTRA_USER_AGENT = "DownloaderActivity_user_agent";
+
+    private final static int MSG_DOWNLOAD_SUCCEEDED = 0;
+    private final static int MSG_DOWNLOAD_FAILED = 1;
+    private final static int MSG_REPORT_PROGRESS = 2;
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_DOWNLOAD_SUCCEEDED:
+                onDownloadSucceeded();
+                break;
+            case MSG_DOWNLOAD_FAILED:
+                onDownloadFailed((String) msg.obj);
+                break;
+            case MSG_REPORT_PROGRESS:
+                onReportProgress(msg.arg1);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown message id "
+                        + msg.what);
+            }
+        }
+
+    };
+
+}
+
diff --git a/src/com/android/quake/PreconditionActivityHelper.java b/src/com/android/quake/PreconditionActivityHelper.java
new file mode 100644
index 0000000..deb0ce0
--- /dev/null
+++ b/src/com/android/quake/PreconditionActivityHelper.java
@@ -0,0 +1,61 @@
+package com.android.quake;
+
+import android.app.Activity;
+import android.content.Intent;
+
+/**
+ * Usage:
+ *
+ * Intent intent = PreconditionActivityHelper.createPreconditionIntent(
+ *     activity, WaitActivity.class);
+ * // Optionally add extras to pass arguments to the intent
+ * intent.putExtra(Utils.EXTRA_ACCOUNT, account);
+ * PreconditionActivityHelper.startPreconditionActivityAndFinish(this, intent);
+ *
+ * // And in the wait activity:
+ * PreconditionActivityHelper.startOriginalActivityAndFinish(this);
+ *
+ */
+
+public class PreconditionActivityHelper {
+    /**
+     * Create a precondition activity intent.
+     * @param activity the original activity
+     * @param preconditionActivityClazz the precondition activity's class
+     * @return an intent which will launch the precondition activity.
+     */
+    public static Intent createPreconditionIntent(Activity activity,
+            Class preconditionActivityClazz) {
+        Intent newIntent = new Intent();
+        newIntent.setClass(activity, preconditionActivityClazz);
+        newIntent.putExtra(EXTRA_WRAPPED_INTENT, activity.getIntent());
+        return newIntent;
+    }
+
+    /**
+     * Start the precondition activity using a given intent, which should
+     * have been created by calling createPreconditionIntent.
+     * @param activity
+     * @param intent
+     */
+    public static void startPreconditionActivityAndFinish(Activity activity,
+            Intent intent) {
+        activity.startActivity(intent);
+        activity.finish();
+    }
+
+    /**
+     * Start the original activity, and finish the precondition activity.
+     * @param preconditionActivity
+     */
+    public static void startOriginalActivityAndFinish(
+            Activity preconditionActivity) {
+        preconditionActivity.startActivity(
+                (Intent) preconditionActivity.getIntent()
+                    .getParcelableExtra(EXTRA_WRAPPED_INTENT));
+        preconditionActivity.finish();
+    }
+
+    static private final String EXTRA_WRAPPED_INTENT =
+        "PreconditionActivityHelper_wrappedIntent";
+}
diff --git a/src/com/android/quake/QuakeActivity.java b/src/com/android/quake/QuakeActivity.java
new file mode 100644
index 0000000..2388dac
--- /dev/null
+++ b/src/com/android/quake/QuakeActivity.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quake;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.File;
+
+
+public class QuakeActivity extends Activity {
+
+    QuakeView mQuakeView;
+
+    static QuakeLib mQuakeLib;
+
+    boolean mKeepScreenOn = true;
+
+    @Override protected void onCreate(Bundle icicle) {
+        Log.i("QuakeActivity", "onCreate");
+        super.onCreate(icicle);
+        if (! DownloaderActivity.ensureDownloaded(this,
+                getString(R.string.quake_customDownloadText), FILE_CONFIG_URL,
+                CONFIG_VERSION, DATA_PATH, USER_AGENT)) {
+            return;
+        }
+
+        if (foundQuakeData()) {
+
+            if (mQuakeLib == null) {
+                mQuakeLib = new QuakeLib();
+                if(! mQuakeLib.init()) {
+                    setContentView(new QuakeViewNoData(
+                            getApplication(),
+                            QuakeViewNoData.E_INITFAILED));
+                    return;
+                }
+            }
+
+            if (mKeepScreenOn) {
+                getWindow().setFlags(
+                        WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
+                        WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+            }
+
+            if (mQuakeView == null) {
+                mQuakeView = new
+                QuakeView(getApplication());
+                mQuakeView.setQuakeLib(mQuakeLib);
+            }
+            setContentView(mQuakeView);
+        }
+        else {
+            setContentView(new QuakeViewNoData(getApplication(),
+                            QuakeViewNoData.E_NODATA));
+        }
+    }
+
+    @Override protected void onPause() {
+        super.onPause();
+        if (mQuakeView != null) {
+            mQuakeView.onPause();
+        }
+    }
+
+    @Override protected void onResume() {
+        super.onResume();
+        if (mQuakeView != null) {
+            mQuakeView.onResume();
+        }
+    }
+
+    @Override protected void onDestroy() {
+        super.onDestroy();
+        if (mQuakeLib != null) {
+            mQuakeLib.quit();
+        }
+    }
+
+    private boolean foundQuakeData() {
+        return fileExists("/sdcard/data/quake/id1/pak0.pak");
+    }
+
+    private boolean fileExists(String s) {
+        File f = new File(s);
+        return f.exists();
+    }
+
+    private final static String FILE_CONFIG_URL =
+        "http://sunnyvale.frotz.net/android/quake/quake11.config";
+    private final static String CONFIG_VERSION = "1.1";
+    private final static String DATA_PATH = "/sdcard/data/quake";
+    private final static String USER_AGENT = "Android Quake Downloader";
+
+}
diff --git a/src/com/android/quake/QuakeLib.java b/src/com/android/quake/QuakeLib.java
new file mode 100644
index 0000000..169624e
--- /dev/null
+++ b/src/com/android/quake/QuakeLib.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quake;
+
+// Wrapper for native quake application
+
+public class QuakeLib {
+
+    public static final int KEY_PRESS = 1;
+    public static final int KEY_RELEASE = 0;
+
+    public static final int MOTION_DOWN = 0;
+    public static final int MOTION_UP = 1;
+    public static final int MOTION_MOVE = 2;
+    public static final int MOTION_CANCEL = 3;
+
+    // copied from Quake keys.h
+    // these are the key numbers that should be passed to Key_Event
+    //
+    //
+    // these are the key numbers that should be passed to Key_Event
+    //
+     public static final int K_TAB           = 9;
+     public static final int K_ENTER         = 13;
+     public static final int K_ESCAPE        = 27;
+     public static final int K_SPACE         = 32;
+
+     // normal keys should be passed as lowercased ascii
+
+     public static final int K_BACKSPACE     = 127;
+     public static final int K_UPARROW       = 128;
+     public static final int K_DOWNARROW     = 129;
+     public static final int K_LEFTARROW     = 130;
+     public static final int K_RIGHTARROW    = 131;
+
+     public static final int K_ALT           = 132;
+     public static final int K_CTRL          = 133;
+     public static final int K_SHIFT         = 134;
+     public static final int K_F1            = 135;
+     public static final int K_F2            = 136;
+     public static final int K_F3            = 137;
+     public static final int K_F4            = 138;
+     public static final int K_F5            = 139;
+     public static final int K_F6            = 140;
+     public static final int K_F7            = 141;
+     public static final int K_F8            = 142;
+     public static final int K_F9            = 143;
+     public static final int K_F10           = 144;
+     public static final int K_F11           = 145;
+     public static final int K_F12           = 146;
+     public static final int K_INS           = 147;
+     public static final int K_DEL           = 148;
+     public static final int K_PGDN          = 149;
+     public static final int K_PGUP          = 150;
+     public static final int K_HOME          = 151;
+     public static final int K_END           = 152;
+
+     public static final int K_PAUSE         = 255;
+
+     //
+     // mouse buttons generate virtual keys
+     //
+     public static final int K_MOUSE1        = 200;
+     public static final int K_MOUSE2        = 201;
+     public static final int K_MOUSE3        = 202;
+
+     //
+     // joystick buttons
+     //
+     public static final int K_JOY1          = 203;
+     public static final int K_JOY2          = 204;
+     public static final int K_JOY3          = 205;
+     public static final int K_JOY4          = 206;
+
+     //
+     // aux keys are for multi-buttoned joysticks to generate so they can use
+     // the normal binding process
+     //
+     public static final int K_AUX1          = 207;
+     public static final int K_AUX2          = 208;
+     public static final int K_AUX3          = 209;
+     public static final int K_AUX4          = 210;
+     public static final int K_AUX5          = 211;
+     public static final int K_AUX6          = 212;
+     public static final int K_AUX7          = 213;
+     public static final int K_AUX8          = 214;
+     public static final int K_AUX9          = 215;
+     public static final int K_AUX10         = 216;
+     public static final int K_AUX11         = 217;
+     public static final int K_AUX12         = 218;
+     public static final int K_AUX13         = 219;
+     public static final int K_AUX14         = 220;
+     public static final int K_AUX15         = 221;
+     public static final int K_AUX16         = 222;
+     public static final int K_AUX17         = 223;
+     public static final int K_AUX18         = 224;
+     public static final int K_AUX19         = 225;
+     public static final int K_AUX20         = 226;
+     public static final int K_AUX21         = 227;
+     public static final int K_AUX22         = 228;
+     public static final int K_AUX23         = 229;
+     public static final int K_AUX24         = 230;
+     public static final int K_AUX25         = 231;
+     public static final int K_AUX26         = 232;
+     public static final int K_AUX27         = 233;
+     public static final int K_AUX28         = 234;
+     public static final int K_AUX29         = 235;
+     public static final int K_AUX30         = 236;
+     public static final int K_AUX31         = 237;
+     public static final int K_AUX32         = 238;
+
+     // JACK: Intellimouse(c) Mouse Wheel Support
+
+     public static final int K_MWHEELUP      = 239;
+     public static final int K_MWHEELDOWN    = 240;
+
+     static {
+         System.loadLibrary("quake");
+     }
+
+     public QuakeLib() {
+     }
+
+     public native boolean init();
+
+    /**
+     * Used to report key events
+     * @param type KEY_PRESS or KEY_RELEASE
+     * @param value the key code.
+     * @return true if the event was handled.
+     */
+     public native boolean event(int type, int value);
+
+    /**
+     * Used to report touch-screen events
+     * @param eventTime the time the event happened
+     * @param action the kind of action being performed -- one of either
+     * {@link #MOTION_DOWN}, {@link #MOTION_MOVE}, {@link #MOTION_UP},
+     * or {@link #MOTION_CANCEL}
+     * @param x the x coordinate in pixels
+     * @param y the y coordinate in pixels
+     * @param pressure the pressure 0..1, can be more than 1 sometimes
+     * @param size the size of the area pressed (radius in X or Y)
+     * @param deviceId the id of the device generating the events
+     * @return true if the event was handled.
+     */
+     public native boolean motionEvent(long eventTime, int action,
+            float x, float y, float pressure, float size, int deviceId);
+
+     /**
+      * Used to report trackball events
+      * @param eventTime the time the event happened
+      * @param action the kind of action being performed -- one of either
+      * {@link #MOTION_DOWN}, {@link #MOTION_MOVE}, {@link #MOTION_UP},
+      * or {@link #MOTION_CANCEL}
+      * @param x the x motion in pixels
+      * @param y the y motion in pixels
+      * @return true if the event was handled.
+      */
+     public native boolean trackballEvent(long eventTime, int action,
+             float x, float y);
+    /**
+     * @param width the current view width
+     * @param height the current view height
+     * @return true if quake is in "game" mode, false if it is in "menu" or
+     * "typing" mode.
+     */
+     public native boolean step(int width, int height);
+
+     /**
+      * Tell Quake to quit. It will write out its config files and so forth.
+      */
+     public native void quit();
+}
diff --git a/src/com/android/quake/QuakeView.java b/src/com/android/quake/QuakeView.java
new file mode 100644
index 0000000..3f99c57
--- /dev/null
+++ b/src/com/android/quake/QuakeView.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quake;
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying an OpenGL animation.  This allows the animation to run in a
+ * separate thread, without requiring that it be driven by the update mechanism
+ * of the view hierarchy.
+ *
+ * The application-specific rendering code is delegated to a GLView.Renderer
+ * instance.
+ */
+class QuakeView extends GLSurfaceView {
+    QuakeView(Context context) {
+        super(context);
+        init();
+    }
+
+    public QuakeView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init() {
+        // We want events.
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        requestFocus();
+    }
+
+    public void setQuakeLib(QuakeLib quakeLib) {
+        mQuakeLib = quakeLib;
+        setRenderer(new QuakeRenderer());
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (!weWantThisKeyCode(keyCode)) {
+            return super.onKeyDown(keyCode, event);
+        }
+        switch (keyCode) {
+        case KeyEvent.KEYCODE_ALT_RIGHT:
+        case KeyEvent.KEYCODE_ALT_LEFT:
+            mAltKeyPressed = true;
+            break;
+        case KeyEvent.KEYCODE_SHIFT_RIGHT:
+        case KeyEvent.KEYCODE_SHIFT_LEFT:
+            mShiftKeyPressed = true;
+            break;
+        }
+        queueKeyEvent(QuakeLib.KEY_PRESS,
+                keyCodeToQuakeCode(keyCode));
+        return true;
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (!weWantThisKeyCode(keyCode)) {
+            return super.onKeyUp(keyCode, event);
+        }
+        switch (keyCode) {
+        case KeyEvent.KEYCODE_ALT_RIGHT:
+        case KeyEvent.KEYCODE_ALT_LEFT:
+            mAltKeyPressed = false;
+            break;
+        case KeyEvent.KEYCODE_SHIFT_RIGHT:
+        case KeyEvent.KEYCODE_SHIFT_LEFT:
+            mShiftKeyPressed = false;
+            break;        }
+        queueKeyEvent(QuakeLib.KEY_RELEASE,
+                keyCodeToQuakeCode(keyCode));
+        return true;
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent event) {
+        if (!mGameMode) {
+            return super.onTrackballEvent(event);
+        }
+        queueTrackballEvent(event);
+        return true;
+    }
+
+    private boolean weWantThisKeyCode(int keyCode) {
+        return (keyCode != KeyEvent.KEYCODE_VOLUME_UP) &&
+            (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN) &&
+            (keyCode != KeyEvent.KEYCODE_SEARCH);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        queueMotionEvent(ev);
+        return true;
+    }
+
+    private int keyCodeToQuakeCode(int keyCode) {
+        int key = 0;
+        if (key >= sKeyCodeToQuakeCode.length) {
+            return 0;
+        }
+        if (mAltKeyPressed) {
+            key = sKeyCodeToQuakeCodeAlt[keyCode];
+            if (key == 0) {
+                key = sKeyCodeToQuakeCodeShift[keyCode];
+                if (key == 0) {
+                    key = sKeyCodeToQuakeCode[keyCode];
+                }
+            }
+        } else if (mShiftKeyPressed) {
+            key = sKeyCodeToQuakeCodeShift[keyCode];
+            if (key == 0) {
+                key = sKeyCodeToQuakeCode[keyCode];
+            }
+        } else {
+            key = sKeyCodeToQuakeCode[keyCode];
+        }
+        if (key == 0) {
+            key = '$';
+        }
+        return key;
+    }
+
+    public void queueKeyEvent(final int type, final int keyCode) {
+        queueEvent(
+            new Runnable() {
+                public void run() {
+                    mQuakeLib.event(type, keyCode);
+                }
+            });
+    }
+
+    public void queueMotionEvent(final MotionEvent ev) {
+        queueEvent(
+            new Runnable() {
+                public void run() {
+                    mQuakeLib.motionEvent(ev.getEventTime(),
+                            ev.getAction(),
+                            ev.getX(), ev.getY(),
+                            ev.getPressure(), ev.getSize(),
+                            ev.getDeviceId());
+                }
+            });
+    }
+
+    public void queueTrackballEvent(final MotionEvent ev) {
+        queueEvent(
+            new Runnable() {
+                public void run() {
+                    mQuakeLib.trackballEvent(ev.getEventTime(),
+                            ev.getAction(),
+                            ev.getX(), ev.getY());
+                }
+            });
+    }
+
+    private boolean mShiftKeyPressed;
+    private boolean mAltKeyPressed;
+
+    private static final int[] sKeyCodeToQuakeCode = {
+        '$', QuakeLib.K_ESCAPE, '$', '$',  QuakeLib.K_ESCAPE, '$', '$', '0', //  0.. 7
+        '1', '2', '3', '4',  '5', '6', '7', '8', //  8..15
+        '9', '$', '$', QuakeLib.K_UPARROW,  QuakeLib.K_DOWNARROW, QuakeLib.K_LEFTARROW, QuakeLib.K_RIGHTARROW, QuakeLib.K_ENTER, // 16..23
+        '$', '$', '$', QuakeLib.K_HOME,  '$', 'a', 'b', 'c', // 24..31
+
+        'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', // 32..39
+        'l', 'm', 'n', 'o',  'p', 'q', 'r', 's', // 40..47
+        't', 'u', 'v', 'w',  'x', 'y', 'z', ',', // 48..55
+        '.', QuakeLib.K_ALT, QuakeLib.K_ALT, QuakeLib.K_SHIFT,  QuakeLib.K_SHIFT, QuakeLib.K_TAB, ' ', '$', // 56..63
+        '$', '$', QuakeLib.K_ENTER, QuakeLib.K_BACKSPACE, '`', '-',  '=', '[', // 64..71
+        ']', '\\', ';', '\'', '/', QuakeLib.K_CTRL,  '#', '$', // 72..79
+        QuakeLib.K_HOME, '$', QuakeLib.K_ESCAPE, '$',  '$'                      // 80..84
+    };
+
+    private static final int sKeyCodeToQuakeCodeShift[] =
+    {
+        0, 0, 0, 0,  0, 0, 0, ')', //  0.. 7
+        '!', '@', '#', '$',  '%', '^', '&', '*', //  8..15
+        '(', 0, 0, 0,  0, 0, 0, 0, // 16..23
+        0, 0, 0, 0,  0, 0, ']', 0, // 24..31
+
+        '\\', '_', '{', '}',  ':', '-', ';', '"', // 32..39
+        '\'', '>', '<', '+',  '=', 0, 0, '|', // 40..47
+        0, 0, '[', '`',  0, 0, QuakeLib.K_PAUSE, ';', // 48..55
+        0, 0, 0, 0,  0, 0, 0, 0, // 56..63
+        0, 0, 0, 0,  0, 0, 0, 0, // 64..71
+        0, 0, '?', '0',  0, QuakeLib.K_CTRL, 0, 0, // 72..79
+        0, 0, 0, 0,  0                       // 80..84
+    };
+
+    private static final int sKeyCodeToQuakeCodeAlt[] =
+    {
+        0, 0, 0, 0,  0, 0, 0, QuakeLib.K_F10, //  0.. 7
+        QuakeLib.K_F1, QuakeLib.K_F2, QuakeLib.K_F3, QuakeLib.K_F4,  QuakeLib.K_F5, QuakeLib.K_F6, QuakeLib.K_F7, QuakeLib.K_F8, //  8..15
+        QuakeLib.K_F9, 0, 0, 0,  0, 0, 0, 0, // 16..23
+        0, 0, 0, 0,  0, 0, 0, 0, // 24..31
+
+        0, 0, 0, 0,  0, 0, 0, 0, // 32..39
+        0, 0, 0, 0,  0, 0, 0, 0, // 40..47
+        QuakeLib.K_F11, 0, 0, 0,  0, QuakeLib.K_F12, 0, 0, // 48..55
+        0, 0, 0, 0,  0, 0, 0, 0, // 56..63
+        0, 0, 0, 0,  0, 0, 0, 0, // 64..71
+        0, 0, 0, 0,  0, 0, 0, 0, // 72..79
+        0, 0, 0, 0,  0           // 80..83
+    };
+
+    private class QuakeRenderer implements GLSurfaceView.Renderer {
+        private static final String TAG = "QuakeRenderer";
+        public void onDrawFrame(GL10 gl) {
+            if (mWidth != 0 &&  mHeight != 0) {
+                mGameMode = mQuakeLib.step(mWidth, mHeight);
+            }
+        }
+
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            mWidth = width;
+            mHeight = height;
+            mQuakeLib.init();
+        }
+
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+            // Do nothing.
+        }
+        private int mWidth;
+        private int mHeight;
+    }
+
+    private QuakeLib mQuakeLib;
+    private boolean mGameMode;
+}
+
diff --git a/src/com/android/quake/QuakeViewNoData.java b/src/com/android/quake/QuakeViewNoData.java
new file mode 100644
index 0000000..760fd83
--- /dev/null
+++ b/src/com/android/quake/QuakeViewNoData.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quake;
+
+import android.view.View;
+import android.content.Context;
+import android.graphics.Paint;
+import android.graphics.Canvas;
+
+public class QuakeViewNoData extends View {
+    public QuakeViewNoData(Context context, int reason)
+    {
+        super(context);
+        mReason = reason;
+    }
+
+    public static final int E_NODATA = 1;
+    public static final int E_INITFAILED = 2;
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        Paint paint = new Paint();
+        paint.setColor(0xffffffff);
+        paint.setStyle(Paint.Style.FILL);
+        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
+        paint.setColor(0xff000000);
+        switch(mReason)
+        {
+            case E_NODATA:
+                canvas.drawText("Missing data files. Looking for one of:",
+                        10.0f, 20.0f, paint);
+                canvas.drawText("/sdcard/data/quake/id1/pak0.pak",
+                        10.0f, 35.0f, paint);
+                canvas.drawText("/data/quake/id1/pak0.pak",
+                        10.0f, 50.0f, paint);
+                canvas.drawText("Please copy a pak file to the device and reboot.",
+                        10.0f, 65.0f, paint);
+                break;
+            case E_INITFAILED:
+                canvas.drawText("Quake C library initialization failed.",
+                        10.0f, 20.0f, paint);
+                canvas.drawText("Try stopping and restarting the simulator.",
+                        10.0f, 35.0f, paint);
+                break;
+        }
+    }
+
+    private int mReason;
+
+}
diff --git a/standalone/main.cpp b/standalone/main.cpp
new file mode 100644
index 0000000..5e7ad76
--- /dev/null
+++ b/standalone/main.cpp
@@ -0,0 +1,360 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <pthread.h>
+#include <ui/EventHub.h>
+#include <ui/EGLDisplaySurface.h>
+
+extern void AndroidInitArgs(int argc, char** argv);
+extern int AndroidInit();
+extern int AndroidMotionEvent(unsigned long long eventTime, int action,
+        float x, float y, float pressure, float size, int deviceId);
+extern int AndroidEvent(int type, int value);
+extern int AndroidStep(int width, int height);
+
+static int gDisplayWidth;
+static int gDisplayHeight;
+static EGLDisplay gDisplay;
+static EGLSurface gSurface;
+static EGLContext gContext;
+
+void checkEGLError(const char* msg) {
+    unsigned int error = eglGetError();
+    if (error != EGL_SUCCESS) {
+        fprintf(stderr, "%s: error %u\n", msg, error);
+    }
+}
+
+void checkGLError(const char* msg) {
+    unsigned int error = glGetError();
+    if (error != GL_NO_ERROR) {
+        fprintf(stderr, "%s: error 0x%04X\n", msg, error);
+    }
+}
+
+static android::sp<android::EventHub> gHub;
+
+class EventQueue {
+private:
+    class Lock {
+    public:
+        Lock(pthread_mutex_t& mutex) {
+            m_pMutex = &mutex;
+            pthread_mutex_lock(m_pMutex);
+        }
+        ~Lock() {
+            pthread_mutex_unlock(m_pMutex);
+        }
+        void wait(pthread_cond_t& cond) {
+            pthread_cond_wait(&cond, m_pMutex);
+        }
+        void signal(pthread_cond_t& cond) {
+            pthread_cond_signal(&cond);
+        }
+    private:
+        pthread_mutex_t* m_pMutex;
+    };
+    
+public:
+    
+    static const int MOTION_ACTION_DOWN = 0;
+    static const int MOTION_ACTION_UP = 1;
+    static const int MOTION_ACTION_MOVE = 2;
+
+// Platform-specific event types.
+
+    static const int EV_DEVICE_ADDED = android::EventHub::DEVICE_ADDED;
+    static const int EV_DEVICE_REMOVED = android::EventHub::DEVICE_REMOVED;
+    
+    struct Event {
+        int32_t deviceId;
+        int32_t type;
+        int32_t scancode;
+        int32_t keycode;
+        uint32_t flags;
+        int32_t value;
+        nsecs_t when;
+    };
+    
+    EventQueue() {
+        m_Head = 0;
+        m_Count = 0;
+        pthread_mutex_init(&m_mutex, NULL);
+        pthread_cond_init(&m_space_available, NULL);
+        startEventThread();
+    }
+    
+    // Returns NULL if no event available.
+    // Call recycleEvent when you're done with the event
+    Event* getEvent() {
+        Event* result = NULL;
+        Lock lock(m_mutex);
+        if (m_Count > 0) {
+            result = m_Events + m_Head;
+        }
+        return result;
+    }
+    
+    void recycleEvent(Event* pEvent) {
+        Lock lock(m_mutex);
+        if (pEvent == m_Events + m_Head && m_Count > 0) {
+            m_Head = incQueue(m_Head);
+            m_Count--;
+            lock.signal(m_space_available);
+        }
+    }
+    
+private:
+    inline size_t incQueue(size_t index) {
+        return modQueue(index + 1);
+    }
+    
+    inline size_t modQueue(size_t index) {
+        return index & EVENT_SIZE_MASK;
+    }
+    
+    void startEventThread() {
+        pthread_create( &m_eventThread, NULL, &staticEventThreadMain, this);
+    }
+    
+    static void* staticEventThreadMain(void* arg) {
+        return ((EventQueue*) arg)->eventThreadMain();
+    }
+    
+    void* eventThreadMain() {
+        gHub = new android::EventHub();
+        while(true) {
+            Event event;
+            bool result = gHub->getEvent(&event.deviceId,
+                    &event.type,
+                    &event.scancode, &event.keycode, &event.flags,
+                    &event.value, &event.when);
+            if (result) {
+                Lock lock(m_mutex);
+                while( m_Count == MAX_EVENTS) {
+                    lock.wait(m_space_available);
+                }
+                m_Events[modQueue(m_Head + m_Count)] = event;
+                m_Count = incQueue(m_Count);
+            }
+        }
+        return NULL;
+    }
+
+    static const size_t MAX_EVENTS = 16;
+    static const size_t EVENT_SIZE_MASK = 0xf;
+    
+    pthread_t m_eventThread;
+    pthread_mutex_t m_mutex;
+    pthread_cond_t  m_space_available;
+    unsigned int m_Head;
+    unsigned int m_Count;
+    Event m_Events[MAX_EVENTS];
+};
+
+bool gNoEvents;
+EventQueue* gpEventQueue;
+
+int init(int argc, char** argv) {
+    
+    for(int i = 0; i < argc; i++) {
+        char* p = argv[i];
+        if (strcmp(p, "-noevents") == 0) {
+            printf("-noevents: will not look for events.\n");
+            gNoEvents = true;
+        }
+    }
+    
+    if (! gNoEvents) {
+        gpEventQueue = new EventQueue();
+    }
+    
+    gDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    
+    EGLint majorVersion;
+    EGLint minorVersion;
+    
+    eglInitialize(gDisplay, &majorVersion, &minorVersion);
+    checkEGLError("eglInitialize");
+        
+    EGLint configRequest[] = {
+            EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5,
+            EGL_DEPTH_SIZE, 16,
+            EGL_STENCIL_SIZE, 0,
+            EGL_NONE
+    };
+ 
+    EGLConfig config;
+    int numConfigs = 0;
+    eglChooseConfig(gDisplay, configRequest, &config, 1, &numConfigs);
+    checkEGLError("eglChooseConfig");
+   
+    gSurface = eglCreateWindowSurface(gDisplay, config,
+            android_createDisplaySurface(), NULL);
+
+    checkEGLError("eglMapWindowSurface");
+
+    eglQuerySurface(gDisplay, gSurface, EGL_WIDTH, &gDisplayWidth);
+    eglQuerySurface(gDisplay, gSurface, EGL_HEIGHT, &gDisplayHeight);
+    fprintf(stderr, "display width = %d, height = %d\n", gDisplayWidth,
+            gDisplayHeight);
+
+    gContext = eglCreateContext(gDisplay, config, NULL, NULL);
+    checkEGLError("eglCreateContext");
+    eglMakeCurrent(gDisplay, gSurface, gSurface, gContext);
+    checkEGLError("eglMakeCurrent");
+    
+    printf("vendor    : %s\n", glGetString(GL_VENDOR));
+    printf("renderer  : %s\n", glGetString(GL_RENDERER));
+    printf("version   : %s\n", glGetString(GL_VERSION));
+    printf("extensions: %s\n", glGetString(GL_EXTENSIONS));
+        
+    return 0;
+}
+
+// Quick and dirty implementation of absolute pointer events...
+
+bool lastAbsDown = false;
+bool absDown = false;
+bool absChanged = false;
+unsigned long long absDownTime = 0;
+int absX = 0;
+int absY = 0;
+int absPressure = 0;
+int absSize = 0;
+int lastAbsX = 0;
+int lastAbsY = 0;
+int lastAbsPressure = 0;
+int lastAbsSize = 0;
+
+
+void checkEvents() {
+    
+    if (gpEventQueue == NULL) {
+        return;
+    }
+    while(true) {
+        EventQueue::Event* pEvent = gpEventQueue->getEvent();
+        if (pEvent == NULL) {
+            return;
+        }
+#if 1
+        printf("Event deviceId: %d, type: %d, scancode: %d,  keyCode: %d, flags: %d, value: %d, when: %llu\n",
+                pEvent->deviceId, pEvent->type, pEvent->scancode,
+                pEvent->keycode, pEvent->flags, pEvent->value, pEvent->when);
+#endif
+        switch (pEvent->type) {
+        case EV_KEY: // Keyboard input
+            if (pEvent->scancode == BTN_TOUCH) {
+                absDown = pEvent->value != 0;
+                absChanged = true;
+            }
+            else {
+                AndroidEvent(pEvent->value, pEvent->keycode);
+            }
+            break;
+            
+        case EV_ABS:
+            if (pEvent->scancode == ABS_X) {
+                absX = pEvent->value;
+                absChanged = true;
+            } else if (pEvent->scancode == ABS_Y) {
+                absY = pEvent->value;
+                absChanged = true;
+            } else if (pEvent->scancode == ABS_PRESSURE) {
+                absPressure = pEvent->value;
+                absChanged = true;
+            } else if (pEvent->scancode == ABS_TOOL_WIDTH) {
+                absSize = pEvent->value;
+                absChanged = true;
+            }
+
+        case EV_SYN:
+        {
+            if (absChanged) {
+                 absChanged = false;
+                 int action;
+                 if (absDown != lastAbsDown) {
+                     lastAbsDown = absDown;
+                     if (absDown) {
+                         action = EventQueue::MOTION_ACTION_DOWN;
+                         absDownTime = pEvent->when;
+                     } else {
+                         action = EventQueue::MOTION_ACTION_UP;
+                         absX = lastAbsX;
+                         absY = lastAbsY;
+                         absPressure = lastAbsPressure;
+                         absSize = lastAbsSize;
+                     }
+                 } else {
+                     action = EventQueue::MOTION_ACTION_MOVE;
+                 }
+                 float scaledX = absX;
+                 float scaledY = absY;
+                 float scaledPressure = 1.0f;
+                 float scaledSize = 0;
+#if 0
+                 if (di != null) {
+                     if (di.absX != null) {
+                         scaledX = ((scaledX-di.absX.minValue)
+                                     / di.absX.range)
+                                 * (mDisplay.getWidth()-1);
+                     }
+                     if (di.absY != null) {
+                         scaledY = ((scaledY-di.absY.minValue)
+                                     / di.absY.range)
+                                 * (mDisplay.getHeight()-1);
+                     }
+                     if (di.absPressure != null) {
+                         scaledPressure = 
+                             ((absPressure-di.absPressure.minValue)
+                                     / (float)di.absPressure.range);
+                     }
+                     if (di.absSize != null) {
+                         scaledSize = 
+                             ((absSize-di.absSize.minValue)
+                                     / (float)di.absSize.range);
+                     }
+                 }
+#endif
+
+                 unsigned long long whenMS = pEvent->when / 1000000;
+                 AndroidMotionEvent(whenMS, action,
+                         scaledX, scaledY, scaledPressure, scaledSize,
+                         pEvent->deviceId);
+                 lastAbsX = absX;
+                 lastAbsY = absY;
+            }
+        }
+        break;
+        
+        default:
+            break;
+        }
+        gpEventQueue->recycleEvent(pEvent);
+    }
+}
+
+int main(int argc, char** argv) {
+    fprintf(stderr, "Welcome to stand-alone Android quake.\n");
+    AndroidInitArgs(argc, argv);
+    
+    int result = init(argc, argv);
+    if (result) {
+        return result;
+    }
+    
+    if (!AndroidInit()) {
+        return 1;
+    }
+
+    while(true) {
+        AndroidStep(gDisplayWidth, gDisplayHeight);
+        checkGLError("AndroidStep");
+        eglSwapBuffers(gDisplay, gSurface);
+        checkEGLError("eglSwapBuffers");
+        checkEvents();
+    }
+    return 0;
+}
diff --git a/tools/dumpms2.py b/tools/dumpms2.py
new file mode 100644
index 0000000..2a89dea
--- /dev/null
+++ b/tools/dumpms2.py
@@ -0,0 +1,79 @@
+#!/usr/bin/python2.4
+#
+# Copyright 2007 The Android Open Source Project
+
+"""Dump Quake ms2 files.
+
+Useful for debugging Quake.
+"""
+
+# ms2 file format
+# int32 numcommands
+# int32 numorder
+# int32 commands[numcommands]
+# int32 vertexorder[numorder]
+#
+# Where a command is
+#
+#    >= 0 --> strip(n)
+#    < 0  --> fan(-n)
+# followed by struct { float s; float t; } st[n];
+
+import array
+import sys
+
+def readInt32(f):
+	a = array.array('i')
+	a.read(f, 1)
+	return a[0]
+
+def readFloat32(f):
+	a = array.array('f')
+	a.read(f, 1)
+	return a[0]
+
+def dumpms2(path):
+	f = open(path, "rw")
+	numCommands = readInt32(f)
+	numOrder = readInt32(f)
+	commandIndex = 0
+	
+	# Seek ahead and read the vertex order information
+	f.seek(4 + 4 + 4 * numCommands)
+	vertexOrder = array.array('i')
+	vertexOrder.read(f, numOrder)
+	
+	# Read commands
+	f.seek(4 + 4)
+	vertexOrderIndex = 0
+	
+	while commandIndex < numCommands:
+		cmd = readInt32(f)
+		commandIndex = commandIndex + 1
+		if cmd == 0:
+			break
+		elif(cmd > 0):
+			# strip
+			print "strip ", cmd
+			for i in range(cmd):
+				s = readFloat32(f)
+				t = readFloat32(f)
+				print "[", i, "] ", vertexOrder[vertexOrderIndex], \
+					" (", s, ",", t, ")"
+				commandIndex += 2
+				vertexOrderIndex += 1
+		else:
+			# fan
+			print "fan ", -cmd
+			for i in range(-cmd):
+				s = readFloat32(f)
+				t = readFloat32(f)
+				print "[", i, "] ", vertexOrder[vertexOrderIndex], \
+					" (", s, ",", t, ")"
+				commandIndex += 2
+				vertexOrderIndex += 1
+	
+	f.close()
+
+if __name__ == '__main__': 
+	dumpms2(sys.argv[1])
diff --git a/tools/packagesharedlib b/tools/packagesharedlib
new file mode 100755
index 0000000..b927707
--- /dev/null
+++ b/tools/packagesharedlib
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Put the Quake shared library into the Quake APK and resign the APK.
+# TODO: Use our own cert instead of a test cert
+
+pushd $OUT/system/app
+mkdir -p lib/armeabi
+mv $OUT/system/lib/libquake.so lib/armeabi
+zip -r Quake.apk lib
+rm -rf lib
+SIGNAPK_JAR=$TOP/out/host/darwin-x86/framework/signapk.jar
+PRIVATE_CERTIFICATE=$TOP/target/product/security/testkey.x509.pem
+PRIVATE_PRIVATE_KEY=$TOP/target/product/security/testkey.pk8
+mv Quake.apk Quake-unsigned.apk
+java -jar $SIGNAPK_JAR $PRIVATE_CERTIFICATE $PRIVATE_PRIVATE_KEY Quake-unsigned.apk Quake.apk
+rm Quake-unsigned.apk
+popd